Distribution of 0 digits in factorial series: Difference between revisions
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
(Add C# implementation) |
||
(9 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
{{task| |
{{task|Mathematics}} |
||
Large Factorials and the Distribution of '0' in base 10 digits. |
|||
Write two programs (or one program with two modes) which run on networked computers, and send some messages between them. |
|||
; About the task: |
|||
The protocol used may be language-specific or not, and should be '''suitable for general distributed programming'''; that is, the ''protocol'' should be generic (not designed just for the particular example application), readily capable of handling the independent communications of many different components of a single application, and the transferring of arbitrary data structures natural for the language. |
|||
We can see that some features of factorial numbers (the series of numbers 1!, 2!, 3!, ...) |
|||
This task is intended to demonstrate high-level communication facilities beyond just creating [[sockets]]. |
|||
come about because such numbers are the product of a series of counting numbers, and so those |
|||
products have predictable factors. For example, all factorials above 1! are even numbers, |
|||
since they have 2 as a factor. Similarly, all factorials from 5! up end in a 0, because they |
|||
have 5 and 2 as factors, and thus have 10 as a factor. In fact, the factorial integers add |
|||
another 0 at the end of the factorial for every step of 5 upward: 5! = 120, 10! = 3628800, |
|||
15! = 1307674368000, 16! = 20922789888000 and so on. |
|||
Because factorial numbers, which quickly become quite large, continue to have another terminal 0 |
|||
=={{header|Ada}}== |
|||
on the right hand side of the number for every factor of 5 added to the factorial product, one might |
|||
{{works with|GNAT GPL|2010}} |
|||
think that the proportion of zeros in a base 10 factorial number might be close to 1/5. However, |
|||
{{works with|PolyORB}} |
|||
though the factorial products add another terminating 0 every factor of 5 multiplied into the product, |
|||
as the numbers become quite large, the number of digits in the factorial product expands exponentially, |
|||
and so the number above the terminating zeros tends toward 10% of each digit from 0 to 1 as the factorial |
|||
becomes larger. Thus, as the factorials become larger, the proportion of 0 digits in the factorial products |
|||
shifts slowly from around 1/5 toward 1/10, since the number of terminating zeros in n! increases only in |
|||
proportion to n, whereas the number of digits of n! in base 10 increases exponentially. |
|||
; The task: |
|||
Ada defines facilities for distributed systems in its standard (Annex E, also called DSA). |
|||
Create a function to calculate the mean of the proportions of 0 digits out of the total digits found in each factorial |
|||
This example works with PolyORB and the GNAT GPL 2010 compiler from AdaCore. |
|||
product from 1! to N!. This proportion of 0 digits in base 10 should be calculated using the number as printed as a base 10 integer. |
|||
Example: for 1 to 6 we have 1!, 2!, 3!, 4!, 5!, 6!, or (1, 2, 6, 24, 120, 720), so we need the mean of |
|||
server.ads: |
|||
(0/1, 0/1, 0/1, 0/2, 1/3, 1/3) = (2/3) (totals of each proportion) / 6 (= N), or 0.1111111... |
|||
<syntaxhighlight lang="ada">package Server is |
|||
pragma Remote_Call_Interface; |
|||
procedure Foo; |
|||
function Bar return Natural; |
|||
end Server;</syntaxhighlight> |
|||
Example: for 1 to 25 the mean of the proportions of 0 digits in the factorial products series of N! with N from 1 to 25 is 0.26787. |
|||
server.adb: |
|||
<syntaxhighlight lang="ada">package body Server is |
|||
Count : Natural := 0; |
|||
Do this task for 1 to N where N is in (100, 1000, and 10000), so, compute the mean of the proportion of 0 digits for each product |
|||
procedure Foo is |
|||
in the series of each of the factorials from 1 to 100, 1 to 1000, and 1 to 10000. |
|||
begin |
|||
Count := Count + 1; |
|||
end Foo; |
|||
; Stretch task: |
|||
function Bar return Natural is |
|||
begin |
|||
return Count; |
|||
end Bar; |
|||
end Server;</syntaxhighlight> |
|||
Find the N in 10000 < N < 50000 where the mean of the proportions of 0 digits in the factorial products from 1 to N |
|||
client.adb: |
|||
permanently falls below 0.16. This task took many hours in the Python example, though I wonder if there is a faster |
|||
<syntaxhighlight lang="ada">with Server; |
|||
algorithm out there. |
|||
with Ada.Text_IO; |
|||
=={{header|11l}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="11l">F facpropzeros(n, verbose = 1B) |
|||
procedure Client is |
|||
V proportions = [0.0] * n |
|||
begin |
|||
V (fac, psum) = (BigInt(1), 0.0) |
|||
Ada.Text_IO.Put_Line ("Calling Foo..."); |
|||
L(i) 0 .< n |
|||
fac *= i + 1 |
|||
Ada.Text_IO.Put_Line ("Calling Bar: " & Integer'Image (Server.Bar)); |
|||
V d = String(fac) |
|||
end Client;</syntaxhighlight> |
|||
psum += sum(d.map(x -> Int(x == ‘0’))) / Float(d.len) |
|||
proportions[i] = psum / (i + 1) |
|||
I verbose |
|||
required config (dsa.cfg): |
|||
print(‘The mean proportion of 0 in factorials from 1 to #. is #..’.format(n, psum / n)) |
|||
<syntaxhighlight lang="ada">configuration DSA is |
|||
pragma Starter (None); |
|||
R proportions |
|||
Server_Partition : Partition := (Server); |
|||
procedure Run_Server is in Server_Partition; |
|||
L(n) [100, 1000, 10000] |
|||
-- Client |
|||
facpropzeros(n)</syntaxhighlight> |
|||
Client_Partition : Partition; |
|||
for Client_Partition'Termination use Local_Termination; |
|||
procedure Client; |
|||
for Client_Partition'Main use Client; |
|||
end DSA;</syntaxhighlight> |
|||
{{out}} |
|||
compilation: |
|||
<pre> |
|||
<pre>$po_gnatdist dsa.cfg |
|||
The mean proportion of 0 in factorials from 1 to 100 is 0.246753186. |
|||
[...] |
|||
The mean proportion of 0 in factorials from 1 to 1000 is 0.203544551. |
|||
------------------------------ |
|||
The mean proportion of 0 in factorials from 1 to 10000 is 0.173003848. |
|||
---- Configuration report ---- |
|||
</pre> |
|||
------------------------------ |
|||
Configuration : |
|||
Name : dsa |
|||
Main : run_server |
|||
Starter : none |
|||
=== Base 1000 version === |
|||
Partition server_partition |
|||
<syntaxhighlight lang="11l">F zinit() |
|||
Main : run_server |
|||
V zc = [0] * 999 |
|||
L(x) 1..9 |
|||
- server (rci) |
|||
zc[x - 1] = 2 |
|||
zc[10 * x - 1] = 2 |
|||
zc[100 * x - 1] = 2 |
|||
L(y) (10.<100).step(10) |
|||
zc[y + x - 1] = 1 |
|||
zc[10 * y + x - 1] = 1 |
|||
zc[10 * (y + x) - 1] = 1 |
|||
R zc |
|||
Environment variables : |
|||
- "POLYORB_DSA_NAME_SERVICE" |
|||
F meanfactorialdigits() |
|||
Partition client_partition |
|||
V zc = zinit() |
|||
V rfs = [1] |
|||
V (total, trail, first) = (0.0, 1, 0) |
|||
L(f) 2 .< 50000 |
|||
- client (normal) |
|||
V (carry, d999, zeroes) = (0, 0, (trail - 1) * 3) |
|||
V (j, l) = (trail, rfs.len) |
|||
L j <= l | carry != 0 |
|||
I j <= l |
|||
carry = rfs[j - 1] * f + carry |
|||
d999 = carry % 1000 |
|||
Environment variables : |
|||
I j <= l |
|||
rfs[j - 1] = d999 |
|||
E |
|||
rfs.append(d999) |
|||
zeroes += I d999 == 0 {3} E zc[d999 - 1] |
|||
------------------------------- |
|||
carry I/= 1000 |
|||
[...]</pre> |
|||
j++ |
|||
L rfs[trail - 1] == 0 |
|||
preparation (run PolyORB name service): |
|||
trail++ |
|||
<pre>$ po_ioc_naming |
|||
POLYORB_CORBA_NAME_SERVICE=IOR:010000002b00000049444[...] |
|||
POLYORB_CORBA_NAME_SERVICE=corbaloc:iiop:1.2@10.200.[...]</pre> |
|||
d999 = rfs.last |
|||
You have to set the environment variable POLYORB_DSA_NAME_SERVICE to one of the two values given by po_ioc_naming for the server/client partitions. |
|||
d999 = I d999 >= 100 {0} E I d999 < 10 {2} E 1 |
|||
zeroes -= d999 |
|||
running server: |
|||
V digits = rfs.len * 3 - d999 |
|||
<pre>$ ./server_partition</pre> |
|||
total += Float(zeroes) / digits |
|||
V ratio = total / f |
|||
I f C [100, 1000, 10000] |
|||
print(‘The mean proportion of zero digits in factorials to #. is #.’.format(f, ratio)) |
|||
I ratio >= 0.16 |
|||
running client: |
|||
first = 0 |
|||
<pre>$ ./client_partition |
|||
E I first == 0 |
|||
Calling Foo... |
|||
first = f |
|||
Calling Bar: 1 |
|||
$ ./client_partition |
|||
Calling Foo... |
|||
Calling Bar: 2</pre> |
|||
print(‘The mean proportion dips permanently below 0.16 at ’first‘.’) |
|||
=={{header|AutoHotkey}}== |
|||
See [[Distributed program/AutoHotkey]]. |
|||
meanfactorialdigits()</syntaxhighlight> |
|||
=={{header|C}}== |
|||
Using PVM [http://www.csm.ornl.gov/pvm/pvm_home.html] |
|||
This program is in a sense both a server and a client, depending on if its task is spawned with a command-line argument: if yes, it spawns another task of the same executible on the parallel virtual machine and waits for it to transmit data; if no, it transmits data and is done. |
|||
<syntaxhighlight lang="c">#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <pvm3.h> |
|||
{{out}} |
|||
int main(int c, char **v) |
|||
<pre> |
|||
{ |
|||
The mean proportion of zero digits in factorials to 100 is 0.246753186 |
|||
int tids[10]; |
|||
The mean proportion of zero digits in factorials to 1000 is 0.203544551 |
|||
int parent, spawn; |
|||
The mean proportion of zero digits in factorials to 10000 is 0.173003848 |
|||
int i_data, i2; |
|||
The mean proportion dips permanently below 0.16 at 47332. |
|||
double f_data; |
|||
</pre> |
|||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="arturo">su: 0.0 |
|||
f: 1 |
|||
lim: 100 |
|||
loop 1..10000 'n [ |
|||
'f * n |
|||
str: to :string f |
|||
'su + (enumerate str 'c -> c = `0`) // size str |
|||
if n = lim [ |
|||
print [n ":" su // n] |
|||
'lim * 10 |
|||
] |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
if (c > 1) { |
|||
spawn = pvm_spawn("/tmp/a.out", 0, PvmTaskDefault, 0, 1, tids); |
|||
if (spawn <= 0) { |
|||
printf("Can't spawn task\n"); |
|||
return 1; |
|||
} |
|||
printf("Spawning successful\n"); |
|||
/* pvm_recv(task_id, msgtag). msgtag identifies what kind of data it is, |
|||
* for here: 1 = (int, double), 2 = (int, int) |
|||
* The receiving order is intentionally swapped, just to show. |
|||
* task_id = -1 means "receive from any task" |
|||
*/ |
|||
pvm_recv(-1, 2); |
|||
pvm_unpackf("%d %d", &i_data, &i2); |
|||
printf("got msg type 2: %d %d\n", i_data, i2); |
|||
pvm_recv(-1, 1); |
|||
pvm_unpackf("%d %lf", &i_data, &f_data); |
|||
printf("got msg type 1: %d %f\n", i_data, f_data); |
|||
} else { |
|||
parent = pvm_parent(); |
|||
pvm_initsend(PvmDataDefault); |
|||
i_data = rand(); |
|||
f_data = (double)rand() / RAND_MAX; |
|||
pvm_packf("%d %lf", i_data, f_data); |
|||
pvm_send(parent, 1); /* send msg type 1 */ |
|||
pvm_initsend(PvmDataDefault); |
|||
i2 = rand(); |
|||
pvm_packf("%d %d", i_data, i2); |
|||
pvm_send(parent, 2); /* send msg type 2 */ |
|||
} |
|||
pvm_exit(); |
|||
return 0; |
|||
}</syntaxhighlight>{{out}}(running it on PVM console, exe is /tmp/a.out)<syntaxhighlight lang="text">pvm> spawn -> /tmp/a.out 1 |
|||
spawn -> /tmp/a.out 1 |
|||
[2] |
|||
1 successful |
|||
t40028 |
|||
pvm> [2:t40029] EOF |
|||
[2:t40028] Spawning successful |
|||
[2:t40028] got msg type 2: 1804289383 1681692777 |
|||
[2:t40028] got msg type 1: 1804289383 0.394383 |
|||
[2:t40028] EOF |
|||
[2] finished</syntaxhighlight> |
|||
<pre>100 : 0.2467531861674322 |
|||
=={{header|C sharp|C#}}== |
|||
1000 : 0.2035445511031646 |
|||
Start the program with "server" parameter to start the server, and "client" to start the client. The client will send data to the server and receive a response. The server will wait for data, display the data received, and send a response. |
|||
10000 : 0.1730038482418671</pre> |
|||
=={{header|C#}}== |
|||
<syntaxhighlight lang="csharp"> |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="C#"> |
|||
using System; |
using System; |
||
using System. |
using System.Collections.Generic; |
||
using System. |
using System.Numerics; |
||
using System.Net.Sockets; |
|||
using System.Runtime.Serialization.Formatters.Binary; |
|||
using System.Threading.Tasks; |
|||
public class DistributionInFactorials |
|||
using static System.Console; |
|||
class DistributedProgramming |
|||
{ |
{ |
||
public static void Main(string[] args) |
|||
const int Port = 555; |
|||
async static Task RunClient() |
|||
{ |
{ |
||
List<int> limits = new List<int> { 100, 1_000, 10_000 }; |
|||
WriteLine("Connecting"); |
|||
foreach (int limit in limits) |
|||
await client.ConnectAsync("localhost", Port); |
|||
using (var stream = client.GetStream()) |
|||
{ |
{ |
||
MeanFactorialDigits(limit); |
|||
var data = Serialize(new SampleData()); |
|||
await stream.WriteAsync(data, 0, data.Length); |
|||
WriteLine("Receiving thanks"); |
|||
var buffer = new byte[80000]; |
|||
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); |
|||
var thanks = (string)Deserialize(buffer, bytesRead); |
|||
WriteLine(thanks); |
|||
} |
} |
||
client.Close(); |
|||
} |
} |
||
private static void MeanFactorialDigits(int limit) |
|||
{ |
{ |
||
BigInteger factorial = BigInteger.One; |
|||
WriteLine("Listening"); |
|||
double proportionSum = 0.0; |
|||
double proportionMean = 0.0; |
|||
var client = await listener.AcceptTcpClientAsync(); |
|||
for (int n = 1; n <= limit; n++) |
|||
{ |
{ |
||
factorial = factorial * n; |
|||
string factorialString = factorial.ToString(); |
|||
int digitCount = factorialString.Length; |
|||
long zeroCount = factorialString.Split('0').Length - 1; |
|||
proportionSum += (double)zeroCount / digitCount; |
|||
WriteLine($"{data.Loot} at {data.Latitude}, {data.Longitude}"); |
|||
proportionMean = proportionSum / n; |
|||
WriteLine("Sending thanks"); |
|||
var thanks = Serialize("Thanks!"); |
|||
await stream.WriteAsync(thanks, 0, thanks.Length); |
|||
} |
} |
||
string result = string.Format("{0:F8}", proportionMean); |
|||
client.Close(); |
|||
Console.WriteLine("Mean proportion of zero digits in factorials from 1 to " + limit + " is " + result); |
|||
listener.Stop(); |
|||
Write("Press a key"); |
|||
ReadKey(); |
|||
} |
|||
static byte[] Serialize(object data) |
|||
{ |
|||
using (var mem = new MemoryStream()) |
|||
{ |
|||
new BinaryFormatter().Serialize(mem, data); |
|||
return mem.ToArray(); |
|||
} |
|||
} |
|||
static object Deserialize(byte[] data, int length) |
|||
{ |
|||
using (var mem = new MemoryStream(data, 0, length)) |
|||
{ |
|||
return new BinaryFormatter().Deserialize(mem); |
|||
} |
|||
} |
|||
static void Main(string[] args) |
|||
{ |
|||
if (args.Length == 0) return; |
|||
switch (args[0]) |
|||
{ |
|||
case "client": RunClient().Wait(); break; |
|||
case "server": RunServer().Wait(); break; |
|||
} |
|||
} |
} |
||
} |
|||
[Serializable] |
|||
class SampleData |
|||
{ |
|||
public decimal Latitude = 44.33190m; |
|||
public decimal Longitude = 114.84129m; |
|||
public string Loot = "140 tonnes of jade"; |
|||
} |
} |
||
</syntaxhighlight> |
</syntaxhighlight> |
||
{{out}} |
|||
<pre> |
|||
Mean proportion of zero digits in factorials from 1 to 100 is 0.24675319 |
|||
Mean proportion of zero digits in factorials from 1 to 1000 is 0.20354455 |
|||
Mean proportion of zero digits in factorials from 1 to 10000 is 0.17300385 |
|||
</pre> |
|||
=={{header| |
=={{header|C++}}== |
||
{{trans|Phix}} |
|||
Uses the <b>rpc</b> library: |
|||
<syntaxhighlight lang="cpp">#include <array> |
|||
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff/blob/master/rpc.d |
|||
#include <chrono> |
|||
#include <iomanip> |
|||
#include <iostream> |
|||
#include <vector> |
|||
auto init_zc() { |
|||
This library is not standard, so this code (by Adam D. Ruppe) could and should be rewritten using more standard means. |
|||
std::array<int, 1000> zc; |
|||
<syntaxhighlight lang="d">import arsd.rpc; |
|||
zc.fill(0); |
|||
zc[0] = 3; |
|||
struct S1 { |
|||
int |
for (int x = 1; x <= 9; ++x) { |
||
zc[x] = 2; |
|||
zc[10 * x] = 2; |
|||
} |
|||
zc[100 * x] = 2; |
|||
for (int y = 10; y <= 90; y += 10) { |
|||
struct S2 { |
|||
zc[y + x] = 1; |
|||
string name; |
|||
zc[10 * y + x] = 1; |
|||
int number; |
|||
zc[10 * (y + x)] = 1; |
|||
} |
|||
} |
|||
interface ExampleNetworkFunctions { |
|||
string sayHello(string name); |
|||
int add(in int a, in int b) const pure nothrow; |
|||
S2 structTest(S1); |
|||
void die(); |
|||
} |
|||
// The server must implement the interface. |
|||
class ExampleServer : ExampleNetworkFunctions { |
|||
override string sayHello(string name) { |
|||
return "Hello, " ~ name; |
|||
} |
} |
||
return zc; |
|||
override int add(in int a, in int b) const pure nothrow { |
|||
return a + b; |
|||
} |
|||
override S2 structTest(S1 a) { |
|||
return S2(a.name, a.number); |
|||
} |
|||
override void die() { |
|||
throw new Exception("death requested"); |
|||
} |
|||
mixin NetworkServer!ExampleNetworkFunctions; |
|||
} |
} |
||
template <typename clock_type> |
|||
class Client { |
|||
auto elapsed(const std::chrono::time_point<clock_type>& t0) { |
|||
mixin NetworkClient!ExampleNetworkFunctions; |
|||
auto t1 = clock_type::now(); |
|||
auto duration = |
|||
std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0); |
|||
return duration.count(); |
|||
} |
} |
||
int main() { |
|||
auto zc = init_zc(); |
|||
auto t0 = std::chrono::high_resolution_clock::now(); |
|||
int trail = 1, first = 0; |
|||
double total = 0; |
|||
auto client = new Client("localhost", 5005); |
|||
std::vector<int> rfs{1}; |
|||
// These work like the interface above, but instead of |
|||
std::cout << std::fixed << std::setprecision(10); |
|||
// returning the value, they take callbacks for success (where |
|||
for (int f = 2; f <= 50000; ++f) { |
|||
// the arg is the retval) and failure (the arg is the |
|||
int carry = 0, d999, zeroes = (trail - 1) * 3, len = rfs.size(); |
|||
// exception). |
|||
for (int j = trail - 1; j < len || carry != 0; ++j) { |
|||
client.sayHello("whoa", (a) { writeln(a); }, null); |
|||
if (j < len) |
|||
carry += rfs[j] * f; |
|||
client.add(10,20, (a){ writeln(a); }, null); |
|||
d999 = carry % 1000; |
|||
client.structTest(S1(20, "cool!"), |
|||
if (j < len) |
|||
rfs[j] = d999; |
|||
else |
|||
client.die(delegate(){ writeln("shouldn't happen"); }, |
|||
rfs.push_back(d999); |
|||
zeroes += zc[d999]; |
|||
carry /= 1000; |
|||
} else { |
|||
} |
|||
auto server = new ExampleServer(5005); |
|||
while (rfs[trail - 1] == 0) |
|||
++trail; |
|||
d999 = rfs.back(); |
|||
d999 = d999 < 100 ? (d999 < 10 ? 2 : 1) : 0; |
|||
zeroes -= d999; |
|||
int digits = rfs.size() * 3 - d999; |
|||
total += double(zeroes) / digits; |
|||
double ratio = total / f; |
|||
if (ratio >= 0.16) |
|||
first = 0; |
|||
else if (first == 0) |
|||
first = f; |
|||
if (f == 100 || f == 1000 || f == 10000) { |
|||
std::cout << "Mean proportion of zero digits in factorials to " << f |
|||
<< " is " << ratio << ". (" << elapsed(t0) << "ms)\n"; |
|||
} |
|||
} |
} |
||
std::cout << "The mean proportion dips permanently below 0.16 at " << first |
|||
<< ". (" << elapsed(t0) << "ms)\n"; |
|||
}</syntaxhighlight> |
}</syntaxhighlight> |
||
{{out}} |
|||
<pre> |
|||
'''Protocol:''' Pluribus |
|||
Mean proportion of zero digits in factorials to 100 is 0.2467531862. (0ms) |
|||
Mean proportion of zero digits in factorials to 1000 is 0.2035445511. (1ms) |
|||
This service cannot be used except by clients which know the URL designating it, messages are encrypted, and the client authenticates the server. However, it is vulnerable to denial-of-service by any client knowing the URL. |
|||
Mean proportion of zero digits in factorials to 10000 is 0.1730038482. (152ms) |
|||
The mean proportion dips permanently below 0.16 at 47332. (4598ms) |
|||
=== Server === |
|||
</pre> |
|||
(The protocol is symmetric; this program is the server only in that it is the one which is started first and exports an object.) |
|||
<syntaxhighlight lang="e">def storage := [].diverge() |
|||
def logService { |
|||
to log(line :String) { |
|||
storage.push([timer.now(), line]) |
|||
} |
|||
to search(substring :String) { |
|||
var matches := [] |
|||
for [time, line] ? (line.startOf(substring) != -1) in storage { |
|||
matches with= [time, line] |
|||
} |
|||
return matches |
|||
} |
|||
} |
|||
introducer.onTheAir() |
|||
def sturdyRef := makeSturdyRef.temp(logService) |
|||
println(<captp>.sturdyToURI(sturdyRef)) |
|||
interp.blockAtTop()</syntaxhighlight> |
|||
This will print the URL of the service and run it until aborted. |
|||
=== Client === |
|||
The URL provided by the server is given as the argument to this program. |
|||
<syntaxhighlight lang="e">def [uri] := interp.getArgs() |
|||
introducer.onTheAir() |
|||
def sturdyRef := <captp>.sturdyFromURI(uri) |
|||
def logService := sturdyRef.getRcvr() |
|||
logService <- log("foot") |
|||
logService <- log("shoe") |
|||
println("Searching...") |
|||
when (def result := logService <- search("foo")) -> { |
|||
for [time, line] in result { |
|||
println(`At $time: $line`) |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Erlang}}== |
|||
The protocol is erlang's own |
|||
=== Server === |
|||
srv.erl |
|||
<syntaxhighlight lang="erlang">-module(srv). |
|||
-export([start/0, wait/0]). |
|||
start() -> |
|||
net_kernel:start([srv,shortnames]), |
|||
erlang:set_cookie(node(), rosetta), |
|||
Pid = spawn(srv,wait,[]), |
|||
register(srv,Pid), |
|||
io:fwrite("~p ready~n",[node(Pid)]), |
|||
ok. |
|||
wait() -> |
|||
receive |
|||
{echo, Pid, Any} -> |
|||
io:fwrite("-> ~p from ~p~n", [Any, node(Pid)]), |
|||
Pid ! {hello, Any}, |
|||
wait(); |
|||
Any -> io:fwrite("Error ~p~n", [Any]) |
|||
end.</syntaxhighlight> |
|||
=== Client === |
|||
client.erl |
|||
<syntaxhighlight lang="erlang">-module(client). |
|||
-export([start/0, wait/0]). |
|||
start() -> |
|||
net_kernel:start([client,shortnames]), |
|||
erlang:set_cookie(node(), rosetta), |
|||
{ok,[[Srv]]} = init:get_argument(server), |
|||
io:fwrite("connecting to ~p~n", [Srv]), |
|||
{srv, list_to_atom(Srv)} ! {echo,self(), hi}, |
|||
wait(), |
|||
ok. |
|||
wait() -> |
|||
receive |
|||
{hello, Any} -> io:fwrite("Received ~p~n", [Any]); |
|||
Any -> io:fwrite("Error ~p~n", [Any]) |
|||
end.</syntaxhighlight> |
|||
running it (*comes later) |
|||
|erlc srv.erl |
|||
|erl -run srv start -noshell |
|||
srv@agneyam ready |
|||
*-> hi from client@agneyam |
|||
|erlc client.erl |
|||
|erl -run client start -run init stop -noshell -server srv@agneyam |
|||
connecting to "srv@agneyam" |
|||
Received hi |
|||
=={{header|Factor}}== |
|||
The protocol is the one provided by Factor (concurrency.distributed, concurrency.messaging) |
|||
Example summary: |
|||
- A server node is listening for messages made of natural data types and structures, and simply prettyprint them. |
|||
- A client node is sending such data structure: an array of one string and one hashtable (with one key/value pair). |
|||
===Server=== |
|||
<syntaxhighlight lang="factor">USING: concurrency.distributed concurrency.messaging threads io.sockets io.servers ; |
|||
QUALIFIED: concurrency.messaging |
|||
: prettyprint-message ( -- ) concurrency.messaging:receive . flush prettyprint-message ; |
|||
[ prettyprint-message ] "logger" spawn dup name>> register-remote-thread |
|||
"127.0.0.1" 9000 <inet4> <node-server> start-server</syntaxhighlight> |
|||
Note: we are using QUALIFIED: with the concurrency.messaging vocabulary because the "receive" word is defined in io.sockets vocabulary too. If someone have a cleaner way to handle this. |
|||
===Client=== |
|||
<syntaxhighlight lang="factor">USING: concurrency.distributed io.sockets ; |
|||
QUALIFIED: concurrency.messaging |
|||
{ "Hello Remote Factor!" H{ { "key1" "value1" } } } |
|||
"127.0.0.1" 9000 <inet4> "logger" <remote-thread> concurrency.messaging:send</syntaxhighlight> |
|||
How to Run: |
|||
- Copy/Paste the server code in an instance of Factor Listener |
|||
- Copy/Paste the client code in another instance of Factor Listener. |
|||
The server node should prettyprint the data structure send by the client: { "Hello Remote Factor!" H{ { "key1" "value1" } } } |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
=== |
===Brute force=== |
||
{{libheader|GMP(Go wrapper)}} |
|||
Package net/rpc in the Go standard library serializes data with the Go-native "gob" type. The example here sends only a single floating point number, but the package will send any user-defined data type, including of course structs with multiple fields. |
|||
{{libheader|Go-rcu}} |
|||
Timings here are 2.8 seconds for the basic task and 182.5 seconds for the stretch goal. |
|||
'''Server:''' |
|||
<syntaxhighlight lang="go">package main |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
" |
"fmt" |
||
" |
big "github.com/ncw/gmp" |
||
" |
"rcu" |
||
"net/http" |
|||
"net/rpc" |
|||
) |
) |
||
type TaxComputer float64 |
|||
func (taxRate TaxComputer) Tax(x float64, r *float64) error { |
|||
if x < 0 { |
|||
return errors.New("Negative values not allowed") |
|||
} |
|||
*r = x * float64(taxRate) |
|||
return nil |
|||
} |
|||
func main() { |
func main() { |
||
fact := big.NewInt(1) |
|||
sum := 0.0 |
|||
rpc.Register(c) |
|||
first := int64(0) |
|||
firstRatio := 0.0 |
|||
fmt.Println("The mean proportion of zero digits in factorials up to the following are:") |
|||
if err != nil { |
|||
for n := int64(1); n <= 50000; n++ { |
|||
log.Fatal(err) |
|||
fact.Mul(fact, big.NewInt(n)) |
|||
bytes := []byte(fact.String()) |
|||
digits := len(bytes) |
|||
zeros := 0 |
|||
for _, b := range bytes { |
|||
if b == '0' { |
|||
zeros++ |
|||
} |
|||
} |
|||
sum += float64(zeros)/float64(digits) |
|||
ratio := sum / float64(n) |
|||
if n == 100 || n == 1000 || n == 10000 { |
|||
fmt.Printf("%6s = %12.10f\n", rcu.Commatize(int(n)), ratio) |
|||
} |
|||
if first > 0 && ratio >= 0.16 { |
|||
first = 0 |
|||
firstRatio = 0.0 |
|||
} else if first == 0 && ratio < 0.16 { |
|||
first = n |
|||
firstRatio = ratio |
|||
} |
|||
} |
} |
||
fmt.Printf("%6s = %12.10f", rcu.Commatize(int(first)), firstRatio) |
|||
http.Serve(listener, nil) |
|||
fmt.Println(" (stays below 0.16 after this)") |
|||
fmt.Printf("%6s = %12.10f\n", "50,000", sum / 50000) |
|||
}</syntaxhighlight> |
}</syntaxhighlight> |
||
'''Client:''' |
|||
<syntaxhighlight lang="go">package main |
|||
{{out}} |
|||
import ( |
|||
"fmt" |
|||
"log" |
|||
"net/rpc" |
|||
) |
|||
func main() { |
|||
client, err := rpc.DialHTTP("tcp", "localhost:1234") |
|||
if err != nil { |
|||
fmt.Println(err) |
|||
return |
|||
} |
|||
amount := 3. |
|||
var tax float64 |
|||
err = client.Call("TaxComputer.Tax", amount, &tax) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
fmt.Printf("Tax on %.2f: %.2f\n", amount, tax) |
|||
}</syntaxhighlight> |
|||
{{out | Client output}} |
|||
<pre> |
<pre> |
||
The mean proportion of zero digits in factorials up to the following are: |
|||
Tax on 3.00: 0.15 |
|||
100 = 0.2467531862 |
|||
1,000 = 0.2035445511 |
|||
10,000 = 0.1730038482 |
|||
47,332 = 0.1599999958 (stays below 0.16 after this) |
|||
50,000 = 0.1596200546 |
|||
</pre> |
</pre> |
||
<br> |
|||
===gRPC=== |
|||
==='String math' and base 1000=== |
|||
See http://www.grpc.io/ |
|||
{{trans|Phix}} |
|||
Much quicker than before with 10,000 now being reached in 0.35 seconds and the stretch goal in about 5.5 seconds. |
|||
The default serialization for gRPC is "protocol buffers." gRPC uses a .proto file to define an interface for the client and server. The .proto has its own syntax, independent of client and server implementation languages. Server and client programs here are Go however. |
|||
'''.proto:''' |
|||
<syntaxhighlight lang="proto">syntax = "proto3"; |
|||
service TaxComputer { |
|||
rpc Tax(Amount) returns (Amount) {} |
|||
} |
|||
message Amount { |
|||
int32 cents = 1; |
|||
}</syntaxhighlight> |
|||
'''Server:''' |
|||
<syntaxhighlight lang="go">package main |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
" |
"fmt" |
||
" |
"rcu" |
||
"golang.org/x/net/context" |
|||
"google.golang.org/grpc" |
|||
"google.golang.org/grpc/grpclog" |
|||
"taxcomputer" |
|||
) |
) |
||
var rfs = []int{1} // reverse factorial(1) in base 1000 |
|||
type taxServer struct { |
|||
var zc = make([]int, 999) |
|||
rate float64 |
|||
} |
|||
func init() { |
|||
func (s *taxServer) Tax(ctx context.Context, |
|||
for x := 1; x <= 9; x++ { |
|||
amt *taxcomputer.Amount) (*taxcomputer.Amount, error) { |
|||
zc[x-1] = 2 // 00x |
|||
if amt.Cents < 0 { |
|||
zc[10*x-1] = 2 // 0x0 |
|||
return nil, errors.New("Negative amounts not allowed") |
|||
zc[100*x-1] = 2 // x00 |
|||
var y = 10 |
|||
for y <= 90 { |
|||
zc[y+x-1] = 1 // 0yx |
|||
zc[10*y+x-1] = 1 // y0x |
|||
zc[10*(y+x)-1] = 1 // yx0 |
|||
y += 10 |
|||
} |
|||
} |
} |
||
return &taxcomputer.Amount{int32(float64(amt.Cents)*s.rate + .5)}, nil |
|||
} |
} |
||
func main() { |
func main() { |
||
total := 0.0 |
|||
listener, err := net.Listen("tcp", ":1234") |
|||
trail := 1 |
|||
first := 0 |
|||
grpclog.Fatalf(err.Error()) |
|||
firstRatio := 0.0 |
|||
fmt.Println("The mean proportion of zero digits in factorials up to the following are:") |
|||
for f := 2; f <= 10000; f++ { |
|||
carry := 0 |
|||
d999 := 0 |
|||
zeros := (trail - 1) * 3 |
|||
j := trail |
|||
l := len(rfs) |
|||
for j <= l || carry != 0 { |
|||
if j <= l { |
|||
carry = rfs[j-1]*f + carry |
|||
} |
|||
d999 = carry % 1000 |
|||
if j <= l { |
|||
rfs[j-1] = d999 |
|||
} else { |
|||
rfs = append(rfs, d999) |
|||
} |
|||
if d999 == 0 { |
|||
zeros += 3 |
|||
} else { |
|||
zeros += zc[d999-1] |
|||
} |
|||
carry /= 1000 |
|||
j++ |
|||
} |
|||
for rfs[trail-1] == 0 { |
|||
trail++ |
|||
} |
|||
// d999 = quick correction for length and zeros |
|||
d999 = rfs[len(rfs)-1] |
|||
if d999 < 100 { |
|||
if d999 < 10 { |
|||
d999 = 2 |
|||
} else { |
|||
d999 = 1 |
|||
} |
|||
} else { |
|||
d999 = 0 |
|||
} |
|||
zeros -= d999 |
|||
digits := len(rfs)*3 - d999 |
|||
total += float64(zeros) / float64(digits) |
|||
ratio := total / float64(f) |
|||
if ratio >= 0.16 { |
|||
first = 0 |
|||
firstRatio = 0.0 |
|||
} else if first == 0 { |
|||
first = f |
|||
firstRatio = ratio |
|||
} |
|||
if f == 100 || f == 1000 || f == 10000 { |
|||
fmt.Printf("%6s = %12.10f\n", rcu.Commatize(f), ratio) |
|||
} |
|||
} |
} |
||
fmt.Printf("%6s = %12.10f", rcu.Commatize(first), firstRatio) |
|||
grpcServer := grpc.NewServer() |
|||
fmt.Println(" (stays below 0.16 after this)") |
|||
taxcomputer.RegisterTaxComputerServer(grpcServer, &taxServer{.05}) |
|||
fmt.Printf("%6s = %12.10f\n", "50,000", total/50000) |
|||
grpcServer.Serve(listener) |
|||
}</syntaxhighlight> |
}</syntaxhighlight> |
||
'''Client:''' |
|||
<syntaxhighlight lang="go">package main |
|||
{{out}} |
|||
import ( |
|||
"fmt" |
|||
"golang.org/x/net/context" |
|||
"google.golang.org/grpc" |
|||
"google.golang.org/grpc/grpclog" |
|||
"taxcomputer" |
|||
) |
|||
func main() { |
|||
conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure()) |
|||
if err != nil { |
|||
grpclog.Fatalf(err.Error()) |
|||
} |
|||
defer conn.Close() |
|||
client := taxcomputer.NewTaxComputerClient(conn) |
|||
amt := &taxcomputer.Amount{300} |
|||
tax, err := client.Tax(context.Background(), amt) |
|||
if err != nil { |
|||
grpclog.Fatalf(err.Error()) |
|||
} |
|||
fmt.Println("Tax on", amt.Cents, "cents is", tax.Cents, "cents") |
|||
}</syntaxhighlight> |
|||
{{out | Client output}} |
|||
<pre> |
<pre> |
||
Same as 'brute force' version. |
|||
Tax on 300 cents is 15 cents |
|||
</pre> |
</pre> |
||
== |
=={{header|Java}}== |
||
<syntaxhighlight lang="java"> |
|||
See https://thrift.apache.org/ |
|||
import java.math.BigInteger; |
|||
'''.thrift''' |
|||
import java.util.List; |
|||
public final class DistributionInFactorials { |
|||
Like gRPC, Thrift requires a language independent interface definition file: |
|||
<syntaxhighlight lang="thrift">service TaxService { |
|||
i32 tax(1: i32 amt) |
|||
}</syntaxhighlight> |
|||
'''Server:''' |
|||
<syntaxhighlight lang="go">package main |
|||
public static void main(String[] aArgs) { |
|||
import ( |
|||
List<Integer> limits = List.of( 100, 1_000, 10_000 ); |
|||
"errors" |
|||
for ( Integer limit : limits ) { |
|||
"log" |
|||
meanFactorialDigits(limit); |
|||
} |
|||
} |
|||
private static void meanFactorialDigits(Integer aLimit) { |
|||
BigInteger factorial = BigInteger.ONE; |
|||
double proportionSum = 0.0; |
|||
double proportionMean = 0.0; |
|||
for ( int n = 1; n <= aLimit; n++ ) { |
|||
factorial = factorial.multiply(BigInteger.valueOf(n)); |
|||
String factorialString = factorial.toString(); |
|||
int digitCount = factorialString.length(); |
|||
long zeroCount = factorialString.chars().filter( ch -> ch == '0' ).count(); |
|||
proportionSum += (double) zeroCount / digitCount; |
|||
proportionMean = proportionSum / n; |
|||
} |
|||
String result = String.format("%.8f", proportionMean); |
|||
System.out.println("Mean proportion of zero digits in factorials from 1 to " + aLimit + " is " + result); |
|||
} |
|||
"git.apache.org/thrift.git/lib/go/thrift" |
|||
"gen-go/tax" |
|||
) |
|||
type taxHandler float64 |
|||
func (r taxHandler) Tax(amt int32) (int32, error) { |
|||
if amt < 0 { |
|||
return 0, errors.New("Negative amounts not allowed") |
|||
} |
|||
return int32(float64(amt)*float64(r) + .5), nil |
|||
} |
} |
||
</syntaxhighlight> |
|||
{{ out }} |
|||
func main() { |
|||
transport, err := thrift.NewTServerSocket("localhost:3141") |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
transFac := thrift.NewTTransportFactory() |
|||
protoFac := thrift.NewTCompactProtocolFactory() |
|||
proc := tax.NewTaxServiceProcessor(taxHandler(.05)) |
|||
s := thrift.NewTSimpleServer4(proc, transport, transFac, protoFac) |
|||
if err := s.Serve(); err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
}</syntaxhighlight> |
|||
'''Client:''' |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"fmt" |
|||
"log" |
|||
"git.apache.org/thrift.git/lib/go/thrift" |
|||
"gen-go/tax" |
|||
) |
|||
func main() { |
|||
transport, err := thrift.NewTSocket("localhost:3141") |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
if err := transport.Open(); err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
protoFac := thrift.NewTCompactProtocolFactory() |
|||
client := tax.NewTaxServiceClientFactory(transport, protoFac) |
|||
amt := int32(300) |
|||
t, err := client.Tax(amt) |
|||
if err != nil { |
|||
log.Print(err) |
|||
} else { |
|||
fmt.Println("tax on", amt, "is", t) |
|||
} |
|||
transport.Close() |
|||
}</syntaxhighlight> |
|||
{{out | Client output}} |
|||
<pre> |
<pre> |
||
Mean proportion of zero digits in factorials from 1 to 100 is 0.24675319 |
|||
tax on 300 is 15 |
|||
Mean proportion of zero digits in factorials from 1 to 1000 is 0.20354455 |
|||
Mean proportion of zero digits in factorials from 1 to 10000 is 0.17300385 |
|||
</pre> |
</pre> |
||
=={{header| |
=={{header|jq}}== |
||
'''Works with jq''' |
|||
See: |
|||
The precision of jq's integer arithmetic is not up to this task, so in the following we borrow from the "BigInt" library and use a string representation of integers. |
|||
* http://www.haskell.org/haskellwiki/HaXR#Server |
|||
* http://www.haskell.org/haskellwiki/HaXR#Client |
|||
Unfortunately, although gojq (the Go implementation of jq) does support unbounded-precision integer arithmetic, it is unsuited for the task because of memory management issues. |
|||
Check license: |
|||
http://www.haskell.org/haskellwiki/HaskellWiki:Copyrights |
|||
'''From BigInt.jq''' |
|||
=={{header|JavaScript}}== |
|||
<syntaxhighlight lang="jq"> |
|||
# multiply two decimal strings, which may be signed (+ or -) |
|||
def long_multiply(num1; num2): |
|||
def stripsign: |
|||
{{works with|node.js}} |
|||
.[0:1] as $a |
|||
| if $a == "-" then [ -1, .[1:]] |
|||
elif $a == "+" then [ 1, .[1:]] |
|||
else [1, .] |
|||
end; |
|||
def adjustsign(sign): |
|||
===Server=== |
|||
if sign == 1 then . else "-" + . end; |
|||
# mult/2 assumes neither argument has a sign |
|||
<syntaxhighlight lang="javascript">var net = require('net') |
|||
def mult(num1;num2): |
|||
(num1 | explode | map(.-48) | reverse) as $a1 |
|||
| (num2 | explode | map(.-48) | reverse) as $a2 |
|||
| reduce range(0; num1|length) as $i1 |
|||
([]; # result |
|||
reduce range(0; num2|length) as $i2 |
|||
(.; |
|||
($i1 + $i2) as $ix |
|||
| ( $a1[$i1] * $a2[$i2] + (if $ix >= length then 0 else .[$ix] end) ) as $r |
|||
| if $r > 9 # carrying |
|||
then |
|||
.[$ix + 1] = ($r / 10 | floor) + (if $ix + 1 >= length then 0 else .[$ix + 1] end ) |
|||
| .[$ix] = $r - ( $r / 10 | floor ) * 10 |
|||
else |
|||
.[$ix] = $r |
|||
end |
|||
) |
|||
) |
|||
| reverse | map(.+48) | implode; |
|||
(num1|stripsign) as $a1 |
|||
var server = net.createServer(function (c){ |
|||
| (num2|stripsign) as $a2 |
|||
c.write('hello\r\n') |
|||
| if $a1[1] == "0" or $a2[1] == "0" then "0" |
|||
c.pipe(c) // echo messages back |
|||
elif $a1[1] == "1" then $a2[1]|adjustsign( $a1[0] * $a2[0] ) |
|||
}) |
|||
elif $a2[1] == "1" then $a1[1]|adjustsign( $a1[0] * $a2[0] ) |
|||
else mult($a1[1]; $a2[1]) | adjustsign( $a1[0] * $a2[0] ) |
|||
server.listen(3000, 'localhost') |
|||
end; |
|||
</syntaxhighlight> |
</syntaxhighlight> |
||
'''The task''' |
|||
<syntaxhighlight lang="jq"> |
|||
def count(s): reduce s as $x (0; .+1); |
|||
def meanfactorialdigits: |
|||
===Client=== |
|||
def digits: tostring | explode; |
|||
<syntaxhighlight lang="javascript">var net = require('net') |
|||
def nzeros: count( .[] | select(. == 48) ); # "0" is 48 |
|||
conn = net.createConnection(3000, '192.168.1.x') |
|||
. as $N |
|||
| 0.16 as $goal |
|||
conn.on('connect', function(){ |
|||
| label $out |
|||
console.log('connected') |
|||
| reduce range( 1; 1+$N ) as $i ( {factorial: "1", proportionsum: 0.0, first: null }; |
|||
conn.write('test') |
|||
.factorial = long_multiply(.factorial; $i|tostring) |
|||
}) |
|||
| (.factorial|digits) as $d |
|||
| .proportionsum += ($d | (nzeros / length)) |
|||
conn.on('data', function(msg){ |
|||
| (.proportionsum / $i) as $propmean |
|||
console.log(msg.toString()) |
|||
| if .first |
|||
})</syntaxhighlight> |
|||
then if $propmean > $goal then .first = null else . end |
|||
elif $propmean <= $goal then .first = $i |
|||
else . |
|||
end) |
|||
| "Mean proportion of zero digits in factorials to \($N) is \(.proportionsum/$N);" + |
|||
(if .first then " mean <= \($goal) from N=\(.first) on." else " goal (\($goal)) unmet." end); |
|||
# The task: |
|||
100, 1000, 10000 | meanfactorialdigits</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216; goal (0.16) unmet. |
|||
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458; goal (0.16) unmet. |
|||
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707; goal (0.16) unmet. |
|||
</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
<syntaxhighlight lang="julia">function meanfactorialdigits(N, goal = 0.0) |
|||
Julia was designed with distributed conmputing. in particular cluster computing, as a primary use target. |
|||
factoril, proportionsum = big"1", 0.0 |
|||
If a group of CPUs, including multiple cores on a single machine or a cluster running with paswordless ssh login, is used, |
|||
for i in 1:N |
|||
the following can be set up as an example: |
|||
factoril *= i |
|||
<syntaxhighlight lang="julia"># From Julia 1.0's online docs. File countheads.jl available to all machines: |
|||
d = digits(factoril) |
|||
zero_proportion_in_fac = count(x -> x == 0, d) / length(d) |
|||
function count_heads(n) |
|||
proportionsum += zero_proportion_in_fac |
|||
c::Int = 0 |
|||
propmean = proportionsum / i |
|||
if i > 15 && propmean <= goal |
|||
println("The mean proportion dips permanently below $goal at $i.") |
|||
break |
|||
end |
|||
if i == N |
|||
println("Mean proportion of zero digits in factorials to $N is ", propmean) |
|||
end |
|||
end |
end |
||
end |
|||
c |
|||
end</syntaxhighlight> |
|||
We then run the following on the primary client: |
|||
<syntaxhighlight lang="julia"> |
|||
using Distributed |
|||
@everywhere include_string(Main, $(read("count_heads.jl", String)), "count_heads.jl") |
|||
@time foreach(meanfactorialdigits, [100, 1000, 10000]) |
|||
a = @spawn count_heads(100000000) # runs on an available processor |
|||
b = @spawn count_heads(100000000) # runs on another available processor |
|||
@time meanfactorialdigits(50000, 0.16) |
|||
println(fetch(a)+fetch(b)) # total heads of 200 million coin flips, half on each CPU |
|||
</syntaxhighlight> |
</syntaxhighlight>{{out}} |
||
<pre> |
|||
100001564 |
|||
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216 |
|||
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458 |
|||
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707 |
|||
3.030182 seconds (297.84 k allocations: 1.669 GiB, 0.83% gc time, 0.28% compilation time) |
|||
The mean proportion dips permanently below 0.16 at 47332. |
|||
179.157788 seconds (3.65 M allocations: 59.696 GiB, 1.11% gc time) |
|||
</pre> |
</pre> |
||
=== Base 1000 version === |
|||
=={{header|LFE}}== |
|||
{{trans|Pascal, Phix}} |
|||
<syntaxhighlight lang="julia">function init_zc() |
|||
zc = zeros(Int, 999) |
|||
for x in 1:9 |
|||
zc[x] = 2 # 00x |
|||
zc[10*x] = 2 # 0x0 |
|||
zc[100*x] = 2 # x00 |
|||
for y in 10:10:90 |
|||
zc[y+x] = 1 # 0yx |
|||
zc[10*y+x] = 1 # y0x |
|||
zc[10*(y+x)] = 1 # yx0 |
|||
end |
|||
end |
|||
return zc |
|||
end |
|||
function meanfactorialzeros(N = 50000, verbose = true) |
|||
The protocol used is the one native to Erlang (and thus native to LFE, Lisp Flavored Erlang). |
|||
zc = init_zc() |
|||
rfs = [1] |
|||
total, trail, first, firstratio = 0.0, 1, 0, 0.0 |
|||
These examples are done completely in the LFE REPL. |
|||
for f in 2:N |
|||
===Server=== |
|||
carry, d999, zeroes = 0, 0, (trail - 1) * 3 |
|||
j, l = trail, length(rfs) |
|||
while j <= l || carry != 0 |
|||
if j <= l |
|||
carry = (rfs[j]) * f + carry |
|||
end |
|||
d999 = carry % 1000 |
|||
if j <= l |
|||
rfs[j] = d999 |
|||
else |
|||
push!(rfs, d999) |
|||
end |
|||
zeroes += (d999 == 0) ? 3 : zc[d999] |
|||
carry ÷= 1000 |
|||
j += 1 |
|||
end |
|||
while rfs[trail] == 0 |
|||
trail += 1 |
|||
end |
|||
# d999 = quick correction for length and zeroes: |
|||
d999 = rfs[end] |
|||
d999 = d999 < 100 ? d999 < 10 ? 2 : 1 : 0 |
|||
zeroes -= d999 |
|||
digits = length(rfs) * 3 - d999 |
|||
total += zeroes / digits |
|||
ratio = total / f |
|||
if ratio >= 0.16 |
|||
first = 0 |
|||
firstratio = 0.0 |
|||
elseif first == 0 |
|||
first = f |
|||
firstratio = ratio |
|||
end |
|||
if f in [100, 1000, 10000] |
|||
verbose && println("Mean proportion of zero digits in factorials to $f is $ratio") |
|||
end |
|||
end |
|||
verbose && println("The mean proportion dips permanently below 0.16 at $first.") |
|||
end |
|||
meanfactorialzeros(100, false) |
|||
In one terminal window, start up the REPL |
|||
@time meanfactorialzeros() |
|||
<syntaxhighlight |
</syntaxhighlight>{{out}} |
||
<pre> |
|||
$ ./bin/lfe |
|||
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216 |
|||
Erlang/OTP 17 [erts-6.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] |
|||
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458 |
|||
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707 |
|||
LFE Shell V6.2 (abort with ^G) |
|||
The mean proportion dips permanently below 0.16 at 47332. |
|||
> |
|||
4.638323 seconds (50.08 k allocations: 7.352 MiB) |
|||
</syntaxhighlight> |
|||
</pre> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
And then enter the following code |
|||
<syntaxhighlight lang="mathematica">ClearAll[ZeroDigitsFractionFactorial] |
|||
ZeroDigitsFractionFactorial[n_Integer] := Module[{m}, |
|||
<syntaxhighlight lang="lisp"> |
|||
m = IntegerDigits[n!]; |
|||
> (defun get-server-name () |
|||
Count[m, 0]/Length[m] |
|||
(list_to_atom (++ "exampleserver@" (element 2 (inet:gethostname))))) |
|||
] |
|||
ZeroDigitsFractionFactorial /@ Range[6] // Mean // N |
|||
> (defun start () |
|||
ZeroDigitsFractionFactorial /@ Range[25] // Mean // N |
|||
(net_kernel:start `(,(get-server-name) shortnames)) |
|||
ZeroDigitsFractionFactorial /@ Range[100] // Mean // N |
|||
(erlang:set_cookie (node) 'rosettaexample) |
|||
ZeroDigitsFractionFactorial /@ Range[1000] // Mean // N |
|||
(let ((pid (spawn #'listen/0))) |
|||
ZeroDigitsFractionFactorial /@ Range[10000] // Mean // N |
|||
(register 'serverref pid) |
|||
(io:format "~p ready~n" (list (node pid))) |
|||
'ok)) |
|||
> (defun listen () |
|||
(receive |
|||
(`#(echo ,pid ,data) |
|||
(io:format "Got ~p from ~p~n" (list data (node pid))) |
|||
(! pid `#(hello ,data)) |
|||
(listen)) |
|||
(x |
|||
(io:format "Unexpected pattern: ~p~n" `(,x))))) |
|||
</syntaxhighlight> |
|||
===Client=== |
|||
In another terminal window, start up another LFE REPL and ender the following code: |
|||
<syntaxhighlight lang="lisp"> |
|||
> (defun get-server-name () |
|||
(list_to_atom (++ "exampleserver@" (element 2 (inet:gethostname))))) |
|||
> (defun send (data) |
|||
(net_kernel:start '(exampleclient shortnames)) |
|||
(erlang:set_cookie (node) 'rosettaexample) |
|||
(io:format "connecting to ~p~n" `(,(get-server-name))) |
|||
(! `#(serverref ,(get-server-name)) `#(echo ,(self) ,data)) |
|||
(receive |
|||
(`#(hello ,data) |
|||
(io:format "Received ~p~n" `(,data))) |
|||
(x |
|||
(io:format "Unexpected pattern: ~p~n" (list x)))) |
|||
'ok) |
|||
</syntaxhighlight> |
|||
To use this code, simply start the server in the server terminal: |
|||
<syntaxhighlight lang="lisp"> |
|||
> (start) |
|||
exampleserver@yourhostname ready |
|||
ok |
|||
(exampleserver@yourhostname)> |
|||
</syntaxhighlight> |
|||
Send some messages from the client terminal: |
|||
<syntaxhighlight lang="lisp"> |
|||
> (send "hi there") |
|||
connecting to exampleserver@yourhostname |
|||
Received "hi there" |
|||
ok |
|||
(exampleclient@yourhostname)> (send 42) |
|||
connecting to exampleserver@yourhostname |
|||
Received 42 |
|||
ok |
|||
(exampleclient@yourhostname)> (send #(key value)) |
|||
connecting to exampleserver@yourhostname |
|||
Received {key,value} |
|||
ok |
|||
(exampleclient@yourhostname)> |
|||
</syntaxhighlight> |
|||
And check out the results back in the server terminal window: |
|||
<syntaxhighlight lang="lisp"> |
|||
Got "hi there" from exampleclient@yourhostname |
|||
Got 42 from exampleclient@yourhostname |
|||
Got {key,value} from exampleclient@yourhostname |
|||
</syntaxhighlight> |
|||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
|||
The following sends a request for a random number to be generated on each of two nodes, these are then transmitted back to be assembled into an array with two elements. Omitting the first line, will cause the program to be run on all configured remote computers. |
|||
<syntaxhighlight lang="mathematica">LaunchKernels[2]; |
|||
ParallelEvaluate[RandomReal[]] |
|||
</syntaxhighlight> |
|||
fracs = ParallelMap[ZeroDigitsFractionFactorial, Range[50000], Method -> ("ItemsPerEvaluation" -> 100)]; |
|||
means = Accumulate[N@fracs]/Range[Length[fracs]]; |
|||
len = LengthWhile[Reverse@means, # < 0.16 &]; |
|||
50000 - len + 1</syntaxhighlight> |
|||
{{out}} |
|||
<pre>0.111111 |
|||
0.267873 |
|||
0.246753 |
|||
0.203545 |
|||
0.173004 |
|||
47332</pre> |
|||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
{{libheader|nanomsg}} |
|||
<syntaxhighlight lang="nim">import os, nanomsg |
|||
===Task=== |
|||
proc sendMsg(s: cint, msg: string) = |
|||
{{libheader|bignum}} |
|||
echo "SENDING \"",msg,"\"" |
|||
<syntaxhighlight lang="nim">import strutils, std/monotimes |
|||
let bytes = s.send(msg.cstring, msg.len + 1, 0) |
|||
import bignum |
|||
assert bytes == msg.len + 1 |
|||
let t0 = getMonoTime() |
|||
proc recvMsg(s: cint) = |
|||
var sum = 0.0 |
|||
var buf: cstring |
|||
var f = newInt(1) |
|||
let bytes = s.recv(addr buf, MSG, 0) |
|||
var lim = 100 |
|||
if bytes > 0: |
|||
for n in 1..10_000: |
|||
echo "RECEIVED \"",buf,"\"" |
|||
f *= n |
|||
discard freemsg buf |
|||
let str = $f |
|||
sum += str.count('0') / str.len |
|||
if n == lim: |
|||
echo n, ":\t", sum / float(n) |
|||
lim *= 10 |
|||
echo() |
|||
echo getMonoTime() - t0</syntaxhighlight> |
|||
{{out}} |
|||
proc sendRecv(s: cint, msg: string) = |
|||
<pre>100: 0.2467531861674322 |
|||
var to: cint = 100 |
|||
1000: 0.2035445511031646 |
|||
discard s.setSockOpt(SOL_SOCKET, RCVTIMEO, addr to, sizeof to) |
|||
10000: 0.1730038482418671 |
|||
while true: |
|||
s.recvMsg |
|||
sleep 1000 |
|||
s.sendMsg msg |
|||
(seconds: 2, nanosecond: 857794404)</pre> |
|||
proc node0(url: string) = |
|||
var s = socket(AF_SP, nanomsg.PAIR) |
|||
assert s >= 0 |
|||
let res = s.bindd url |
|||
assert res >= 0 |
|||
s.sendRecv "node0" |
|||
discard s.shutdown 0 |
|||
===Stretch task=== |
|||
proc node1(url: string) = |
|||
{{libheader|bignum}} |
|||
var s = socket(AF_SP, nanomsg.PAIR) |
|||
At each step, we eliminate the trailing zeroes to reduce the length of the number and save some time. But this is not much, about 8%. |
|||
assert s >= 0 |
|||
let res = s.connect url |
|||
assert res >= 0 |
|||
s.sendRecv "node1" |
|||
discard s.shutdown 0 |
|||
<syntaxhighlight lang="nim">import strutils, std/monotimes |
|||
if paramStr(1) == "node0": |
|||
import bignum |
|||
node0 paramStr(2) |
|||
elif paramStr(1) == "node1": |
|||
node1 paramStr(2)</syntaxhighlight> |
|||
Usage: |
|||
<pre>./pair node0 tcp://127.0.0.1:25000 |
|||
./pair node1 tcp://127.0.0.1:25000</pre> |
|||
let t0 = getMonoTime() |
|||
=={{header|Objective-C}}== |
|||
var sum = 0.0 |
|||
Distributed Objects are ''natural'' to Objective-C, and OpenStep and derivated framework offers an easy way of ''using'' remote objects as if it were local. The client must only know the protocol the remote object support. For the rest, calling a remote object's method or local object's method is transparent. |
|||
var first = 0 |
|||
var f = newInt(1) |
|||
var count0 = 0 |
|||
for n in 1..<50_000: |
|||
f *= n |
|||
while f mod 10 == 0: # Reduce the length of "f". |
|||
f = f div 10 |
|||
inc count0 |
|||
let str = $f |
|||
sum += (str.count('0') + count0) / (str.len + count0) |
|||
if sum / float(n) < 0.16: |
|||
if first == 0: first = n |
|||
else: |
|||
first = 0 |
|||
echo "Permanently below 0.16 at n = ", first |
|||
{{works with|GNUstep}} |
|||
echo "Execution time: ", getMonoTime() - t0</syntaxhighlight> |
|||
===Server=== |
|||
The server ''vending'' the object with the name <tt>DistributedAction</tt> |
|||
{{out}} |
|||
<tt>ActionObjectProtocol.h</tt> |
|||
<pre>Permanently below 0.16 at n = 47332 |
|||
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h> |
|||
Execution time: (seconds: 190, nanosecond: 215845101)</pre> |
|||
// our protocol allows "sending" "strings", but we can implement |
|||
=={{header|Pascal}}== |
|||
// everything we could for a "local" object |
|||
Doing the calculation in Base 1,000,000,000 like in [[Primorial_numbers#alternative]].<BR> |
|||
@protocol ActionObjectProtocol |
|||
The most time consuming is converting to string and search for zeros.<BR> |
|||
- (NSString *)sendMessage: (NSString *)msg; |
|||
Therefor I do not convert to string.I divide the base in sections of 3 digits with counting zeros in a lookup table. |
|||
@end</syntaxhighlight> |
|||
<syntaxhighlight lang="pascal">program Factorial; |
|||
{$IFDEF FPC} {$MODE DELPHI} {$Optimization ON,ALL} {$ENDIF} |
|||
uses |
|||
sysutils; |
|||
type |
|||
tMul = array of LongWord; |
|||
tpMul = pLongWord; |
|||
const |
|||
LongWordDec = 1000*1000*1000; |
|||
LIMIT = 50000; |
|||
var |
|||
CountOfZero : array[0..999] of byte; |
|||
SumOfRatio :array[0..LIMIT] of extended; |
|||
<tt>ActionObject.h</tt> |
|||
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h> |
|||
#import "ActionObjectProtocol.h" |
|||
procedure OutMul(pMul:tpMul;Lmt :NativeInt); |
|||
@interface ActionObject : NSObject <ActionObjectProtocol> |
|||
// for testing |
|||
// we do not have much for this example! |
|||
Begin |
|||
@end</syntaxhighlight> |
|||
write(pMul[lmt]); |
|||
For lmt := lmt-1 downto 0 do |
|||
write(Format('%.9d',[pMul[lmt]])); |
|||
writeln; |
|||
end; |
|||
procedure InitCoZ; |
|||
<tt>ActionObject.m</tt> |
|||
//Init Lookup table for 3 digits |
|||
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h> |
|||
var |
|||
#import "ActionObject.h" |
|||
x,y : integer; |
|||
begin |
|||
fillchar(CountOfZero,SizeOf(CountOfZero),#0); |
|||
CountOfZero[0] := 3; //000 |
|||
For x := 1 to 9 do |
|||
Begin |
|||
CountOfZero[x] := 2; //00x |
|||
CountOfZero[10*x] := 2; //0x0 |
|||
CountOfZero[100*x] := 2; //x00 |
|||
y := 10; |
|||
repeat |
|||
CountOfZero[y+x] := 1; //0yx |
|||
CountOfZero[10*y+x] := 1; //y0x |
|||
CountOfZero[10*(y+x)] := 1; //yx0 |
|||
inc(y,10) |
|||
until y > 100; |
|||
end; |
|||
end; |
|||
function getFactorialDecDigits(n:NativeInt):NativeInt; |
|||
@implementation ActionObject |
|||
var |
|||
-(NSString *)sendMessage: (NSString *)msg |
|||
res: extended; |
|||
{ |
|||
Begin |
|||
NSLog(@"client sending message %@", msg); |
|||
result := -1; |
|||
return @"server answers ..."; |
|||
IF (n > 0) AND (n <= 1000*1000) then |
|||
} |
|||
Begin |
|||
@end</syntaxhighlight> |
|||
res := 0; |
|||
repeat res := res+ln(n); dec(n); until n < 2; |
|||
result := trunc(res/ln(10))+1; |
|||
end; |
|||
end; |
|||
function CntZero(pMul:tpMul;Lmt :NativeInt):NativeUint; |
|||
<tt>server.m</tt> |
|||
//count zeros in Base 1,000,000,000 number |
|||
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h> |
|||
var |
|||
#import "ActionObject.h" |
|||
q,r : LongWord; |
|||
i : NativeInt; |
|||
begin |
|||
result := 0; |
|||
For i := Lmt-1 downto 0 do |
|||
Begin |
|||
q := pMul[i]; |
|||
r := q DIV 1000; |
|||
result +=CountOfZero[q-1000*r];//q-1000*r == q mod 1000 |
|||
q := r; |
|||
r := q DIV 1000; |
|||
result +=CountOfZero[q-1000*r]; |
|||
q := r; |
|||
r := q DIV 1000; |
|||
result +=CountOfZero[q-1000*r]; |
|||
end; |
|||
//special case first digits no leading '0' |
|||
q := pMul[lmt]; |
|||
while q >= 1000 do |
|||
begin |
|||
r := q DIV 1000; |
|||
result +=CountOfZero[q-1000*r]; |
|||
q := r; |
|||
end; |
|||
while q > 0 do |
|||
begin |
|||
r := q DIV 10; |
|||
result += Ord( q-10*r= 0); |
|||
q := r; |
|||
end; |
|||
end; |
|||
function GetCoD(pMul:tpMul;Lmt :NativeInt):NativeUint; |
|||
int main (void) |
|||
//count of decimal digits |
|||
{ |
|||
var |
|||
@autoreleasepool { |
|||
i : longWord; |
|||
begin |
|||
ActionObject *action = [[ActionObject alloc] init]; |
|||
result := 9*Lmt; |
|||
i := pMul[Lmt]; |
|||
while i > 1000 do |
|||
begin |
|||
i := i DIV 1000; |
|||
inc(result,3); |
|||
end; |
|||
while i > 0 do |
|||
begin |
|||
i := i DIV 10; |
|||
inc(result); |
|||
end; |
|||
end; |
|||
procedure DoChecks(pMul:tpMul;Lmt,i :NativeInt); |
|||
NSSocketPort *port = (NSSocketPort *)[NSSocketPort port]; |
|||
//(extended(1.0)* makes TIO.RUN faster // only using FPU? |
|||
// initWithTCPPort: 1234 and other methods are not supported yet |
|||
Begin |
|||
// by GNUstep |
|||
SumOfRatio[i] := SumOfRatio[i-1] + (extended(1.0)*CntZero(pMul,Lmt))/GetCoD(pMul,Lmt); |
|||
NSConnection *connect = [NSConnection |
|||
end; |
|||
connectionWithReceivePort: port |
|||
sendPort: port]; // or sendPort: nil |
|||
function MulByI(pMul:tpMul;UL,i :NativeInt):NativeInt; |
|||
[connect setRootObject: action]; |
|||
var |
|||
prod : Uint64; |
|||
j : nativeInt; |
|||
carry : LongWord; |
|||
begin |
|||
result := UL; |
|||
carry := 0; |
|||
For j := 0 to result do |
|||
Begin |
|||
prod := i*pMul[0]+Carry; |
|||
Carry := prod Div LongWordDec; |
|||
pMul[0] := Prod - LongWordDec*Carry; |
|||
inc(pMul); |
|||
end; |
|||
IF Carry <> 0 then |
|||
/* "vend" the object ActionObject as DistributedAction; on GNUstep |
|||
Begin |
|||
the Name Server that allows the resolution of the registered name |
|||
inc(result); |
|||
is bound to port 538 */ |
|||
pMul[0]:= Carry; |
|||
if (![connect registerName:@"DistributedAction" |
|||
End; |
|||
withNameServer: [NSSocketPortNameServer sharedInstance] ]) |
|||
end; |
|||
{ |
|||
NSLog(@"can't register the server DistributedAction"); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
NSLog(@"waiting for messages..."); |
|||
procedure getFactorialExact(n:NativeInt); |
|||
[[NSRunLoop currentRunLoop] run]; |
|||
var |
|||
MulArr : tMul; |
|||
pMul : tpMul; |
|||
i,ul : NativeInt; |
|||
begin |
|||
i := getFactorialDecDigits(n) DIV 9 +10; |
|||
Setlength(MulArr,i); |
|||
pMul := @MulArr[0]; |
|||
Ul := 0; |
|||
pMul[Ul]:= 1; |
|||
i := 1; |
|||
repeat |
|||
UL := MulByI(pMul,UL,i); |
|||
//Now do what you like to do with i! |
|||
DoChecks(pMul,UL,i); |
|||
inc(i); |
|||
until i> n; |
|||
end; |
|||
procedure Out_(i: integer); |
|||
} |
|||
begin |
|||
return 0; |
|||
if i > LIMIT then |
|||
}</syntaxhighlight> |
|||
EXIT; |
|||
writeln(i:8,SumOfRatio[i]/i:18:15); |
|||
===Client=== |
|||
end; |
|||
<tt>client.m</tt> |
|||
<syntaxhighlight lang="objc">#import <Foundation/Foundation.h> |
|||
#import "ActionObjectProtocol.h" |
|||
int main(void) |
|||
{ |
|||
@autoreleasepool { |
|||
id <ActionObjectProtocol> action = (id <ActionObjectProtocol>) |
|||
[NSConnection |
|||
rootProxyForConnectionWithRegisteredName: @"DistributedAction" |
|||
host: @"localhost" |
|||
usingNameServer: [NSSocketPortNameServer sharedInstance] ]; |
|||
if (action == nil) |
|||
{ |
|||
NSLog(@"can't connect to the server"); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
NSArray *args = [[NSProcessInfo processInfo] arguments]; |
|||
if ([args count] == 1) |
|||
{ |
|||
NSLog(@"specify a message"); |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
NSString *msg = args[1]; |
|||
// "send" (call the selector "sendMessage:" of the (remote) object |
|||
// action) the first argument's text as msg, store the message "sent |
|||
// back" and then show it in the log |
|||
NSString *backmsg = [action sendMessage: msg]; |
|||
NSLog("%@", backmsg); |
|||
} |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
=={{header|OCaml}}== |
|||
{{works with|JoCaml}} |
|||
Minimalistic distributed logger with synchronous channels using the join calculus on top of OCaml. |
|||
=== Server === |
|||
<syntaxhighlight lang="ocaml">open Printf |
|||
let create_logger () = |
|||
def log(text) & logs(l) = |
|||
printf "Logged: %s\n%!" text; |
|||
logs((text, Unix.gettimeofday ())::l) & reply to log |
|||
or search(text) & logs(l) = |
|||
logs(l) & reply List.filter (fun (line, _) -> line = text) l to search |
|||
in |
|||
spawn logs([]); |
|||
(log, search) |
|||
def wait() & finished() = reply to wait |
|||
let register name service = Join.Ns.register Join.Ns.here name service |
|||
let () = |
|||
let log, search = create_logger () in |
|||
register "log" log; |
|||
register "search" search; |
|||
Join.Site.listen (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345)); |
|||
wait ()</syntaxhighlight> |
|||
=== Client === |
|||
<syntaxhighlight lang="ocaml">open Printf |
|||
let ns_there = Join.Ns.there (Unix.ADDR_INET (Join.Site.get_local_addr(), 12345)) |
|||
let lookup name = Join.Ns.lookup ns_there name |
|||
let log : string -> unit = lookup "log" |
|||
let search : string -> (string * float) list = lookup "search" |
|||
let find txt = |
|||
printf "Looking for %s...\n" txt; |
|||
List.iter (fun (line, time) -> |
|||
printf "Found: '%s' at t = %f\n%!" (String.escaped line) time) |
|||
(search txt) |
|||
let () = |
|||
log "bar"; |
|||
find "foo"; |
|||
log "foo"; |
|||
log "shoe"; |
|||
find "foo"</syntaxhighlight> |
|||
=={{header|Oz}}== |
|||
We show a program that starts a server on a remote machine, exchanges two messages with that server and finally shuts it down. |
|||
<syntaxhighlight lang="oz">declare |
|||
functor ServerCode |
|||
export |
|||
port:Prt |
|||
define |
|||
Stream |
|||
Prt = {NewPort ?Stream} |
|||
thread |
|||
for Request#Reply in Stream do |
|||
case Request |
|||
of echo(Data) then Reply = Data |
|||
[] compute(Function) then Reply = {Function} |
|||
end |
|||
end |
|||
end |
|||
end |
|||
%% create the server on some machine |
|||
%% (just change "localhost" to some machine |
|||
%% that you can use with a passwordless rsh login |
|||
%% and that has the same Mozart version installed) |
|||
RM = {New Remote.manager init(host:localhost)} |
|||
%% execute the code encapsulated in the ServerCode functor |
|||
Server = {RM apply(ServerCode $)} |
|||
%% Shortcut: send a message to Server and receive a reply |
|||
fun {Send X} |
|||
{Port.sendRecv Server.port X} |
|||
end |
|||
in |
|||
%% echo |
|||
{System.showInfo "Echo reply: "#{Send echo(hello)}} |
|||
%% compute |
|||
{System.showInfo "Result of computation: "# |
|||
{Send compute(fun {$} 8 div 4 end)}} |
|||
%% shut down server |
|||
{RM close}</syntaxhighlight> |
|||
var |
|||
i : integer; |
|||
Begin |
|||
InitCoZ; |
|||
SumOfRatio[0]:= 0; |
|||
getFactorialExact(LIMIT); |
|||
Out_(100); |
|||
Out_(1000); |
|||
Out_(10000); |
|||
Out_(50000); |
|||
i := limit; |
|||
while i >0 do |
|||
Begin |
|||
if SumOfRatio[i]/i >0.16 then |
|||
break; |
|||
dec(i); |
|||
end; |
|||
inc(i); |
|||
writeln('First ratio < 0.16 ', i:8,SumOfRatio[i]/i:20:17); |
|||
end.</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 100 0.246753186167432 |
|||
1000 0.203544551103165 |
|||
10000 0.173003848241866 |
|||
50000 0.159620054602269 |
|||
First ratio < 0.16 47332 0.15999999579985665 |
|||
Real time: 4.898 s CPU share: 99.55 % // 2.67s on 2200G freepascal 3.2.2</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
{{libheader|ntheory}} |
|||
Using Data::Dumper and Safe to transmit arbitrary data structures as serialized text between hosts. Same code works as both sender and receiver. |
|||
<syntaxhighlight lang="perl">use |
<syntaxhighlight lang="perl">use strict; |
||
use |
use warnings; |
||
use ntheory qw/factorial/; |
|||
use Safe; |
|||
for my $n (100, 1000, 10000) { |
|||
sub get_data { |
|||
my($sum,$f) = 0; |
|||
my $sock = new IO::Socket::INET |
|||
$f = factorial $_ and $sum += ($f =~ tr/0//) / length $f for 1..$n; |
|||
LocalHost => "localhost", |
|||
printf "%5d: %.5f\n", $n, $sum/$n; |
|||
LocalPort => "10000", |
|||
Proto => "tcp", |
|||
Listen => 1, |
|||
Reuse => 1; |
|||
unless ($sock) { die "Socket creation failure" } |
|||
my $cli = $sock->accept(); |
|||
# of course someone may be tempted to send you 'system("rm -rf /")', |
|||
# to be safe(r), use Safe:: |
|||
my $safe = new Safe; |
|||
my $x = $safe->reval(join("", <$cli>)); |
|||
close $cli; |
|||
close $sock; |
|||
return $x; |
|||
} |
|||
sub send_data { |
|||
my $host = shift; |
|||
my $data = shift; |
|||
my $sock = new IO::Socket::INET |
|||
PeerAddr => "$host:10000", |
|||
Proto => "tcp", |
|||
Reuse => 1; |
|||
unless ($sock) { die "Socket creation failure" } |
|||
print $sock Data::Dumper->Dump([$data]); |
|||
close $sock; |
|||
} |
|||
if (@ARGV) { |
|||
my $x = get_data(); |
|||
print "Got data\n", Data::Dumper->Dump([$x]); |
|||
} else { |
|||
send_data('some_host', { a=>100, b=>[1 .. 10] }); |
|||
}</syntaxhighlight> |
}</syntaxhighlight> |
||
{{out}} |
|||
<pre> 100: 0.24675 |
|||
1000: 0.20354 |
|||
10000: 0.17300</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Using "string math" to create reversed factorials, for slightly easier skipping of "trailing" zeroes, |
|||
From/using [http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Libzmq the ZeroMQ wrapper from PCAN], a suitable simple publish/subscriber pair. |
|||
but converted to base 1000 and with the zero counting idea from Pascal, which sped it up threefold. |
|||
There is also a server/client/broker example. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
Obviously you can trivially serialize() and deserialize() any Phix data to and from a string. |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<!--<syntaxhighlight lang="phix">(notonline)--> |
|||
<span style="color: # |
<span style="color: #004080;">sequence</span> <span style="color: #000000;">rfs</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- reverse factorial(1) in base 1000</span> |
||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"durapub:\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;"> |
<span style="color: #008080;">function</span> <span style="color: #000000;">init_zc</span><span style="color: #0000FF;">()</span> |
||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">zc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">999</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- 00x</span> |
|||
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- 0x0</span> |
|||
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">100</span><span style="color: #0000FF;">*</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- x00</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">10</span> <span style="color: #008080;">to</span> <span style="color: #000000;">90</span> <span style="color: #008080;">by</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- 0yx</span> |
|||
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- y0x</span> |
|||
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- yx0</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">zc</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">zc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_zc</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;"> |
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span> |
||
<span style="color: #000000;">total</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">trail</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span><span style="color: #0000FF;">?</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">:</span><span style="color: #000000;">50000</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d999</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">trail</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">trail</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">or</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">])*</span><span style="color: #000000;">f</span><span style="color: #0000FF;">+</span><span style="color: #000000;">carry</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">d999</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #000000;">rfs</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">d999</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">+=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">3</span><span style="color: #0000FF;">:</span><span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d999</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">/</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">j</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">trail</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span> <span style="color: #000000;">trail</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
|||
<span style="color: #000080;font-style:italic;">-- d999 := quick correction for length and zeroes:</span> |
|||
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rfs</span><span style="color: #0000FF;">[$]</span> |
|||
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;"><</span><span style="color: #000000;">100</span><span style="color: #0000FF;">?</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;"><</span><span style="color: #000000;">10</span><span style="color: #0000FF;">?</span><span style="color: #000000;">2</span><span style="color: #0000FF;">:</span><span style="color: #000000;">1</span><span style="color: #0000FF;">):</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">d999</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">3</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d999</span> |
|||
<span style="color: #000000;">total</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">zeroes</span><span style="color: #0000FF;">/</span><span style="color: #000000;">digits</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">ratio</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">total</span><span style="color: #0000FF;">/</span><span style="color: #000000;">f</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">ratio</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">0.16</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">--// broadcast 10 updates, with pause</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Mean proportion of zero digits in factorials to %d is %.10f (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ratio</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Update %d"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span> <span style="color: #000000;">update_nbr</span> <span style="color: #0000FF;">})</span> |
|||
<span style="color: #000000;">zmq_s_send</span><span style="color: #0000FF;">(</span><span style="color: #000000;">publisher</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The mean proportion dips permanently below 0.16 at %d. (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">first</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">zmq_close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sync</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">zmq_close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">publisher</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">zmq_term</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">)</span> |
|||
<!--</syntaxhighlight>--> |
<!--</syntaxhighlight>--> |
||
{{out}} |
|||
<pre> |
|||
<!--<syntaxhighlight lang="phix">(notonline)--> |
|||
Mean proportion of zero digits in factorials to 100 is 0.2467531862 (0s) |
|||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (zmq dll/so)</span> |
|||
Mean proportion of zero digits in factorials to 1000 is 0.2035445511 (0.2s) |
|||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"durasub:\n"</span><span style="color: #0000FF;">)</span> |
|||
Mean proportion of zero digits in factorials to 10000 is 0.1730038482 (2.3s) |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">zmq</span><span style="color: #0000FF;">/</span><span style="color: #000000;">zmq</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
The mean proportion dips permanently below 0.16 at 47332. (1 minute and 2s) |
|||
</pre> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">context</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_init</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
<small>(stretch goal removed under pwa/p2js since otherwise you'd get a blank screen for 2 or 3 minutes)</small> |
|||
<span style="color: #000000;">zmq_assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"zmq_init"</span><span style="color: #0000FF;">)</span> |
|||
=== trailing zeroes only === |
|||
Should you only be interested in the ratio of trailing zeroes, you can do that much faster: |
|||
<span style="color: #000080;font-style:italic;">--// connect our subscriber socket</span> |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">subscriber</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">zmq_socket</span><span style="color: #0000FF;">(</span><span style="color: #000000;">context</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ZMQ_SUB</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: # |
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
||
<span style="color: # |
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span> |
||
<span style="color: #000000;">f10</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">log10</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">total</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: # |
<span style="color: #004080;">integer</span> <span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
||
<span style="color: #008080;">for</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">50000</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">f10</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">log10</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">--// synchronise with publisher</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">ceil</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f10</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">5</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #000000;">v</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">f</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">/</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">--// get updates, Ctrl-C break</span> |
|||
<span style="color: #000000;">v</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">5</span> |
|||
<span style="color: # |
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
||
<span style="color: # |
<span style="color: #000000;">total</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">zeroes</span><span style="color: #0000FF;">/</span><span style="color: #000000;">digits</span> |
||
<span style="color: # |
<span style="color: #004080;">atom</span> <span style="color: #000000;">ratio</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">total</span><span style="color: #0000FF;">/</span><span style="color: #000000;">f</span> |
||
<span style="color: #008080;">if</span> <span style="color: #000000;">ratio</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">0.07</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Mean proportion of trailing zeroes in factorials to %d is %f\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ratio</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The mean proportion dips permanently below 0.07 at %d. (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">first</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span> |
|||
<!--</syntaxhighlight>--> |
<!--</syntaxhighlight>--> |
||
{{out}} |
|||
<pre> |
|||
=={{header|PicoLisp}}== |
|||
Mean proportion of trailing zeroes in factorials to 100 is 0.170338 |
|||
===Server=== |
|||
Mean proportion of trailing zeroes in factorials to 1000 is 0.116334 |
|||
<syntaxhighlight lang="picolisp">(task (port 12321) # Background server task |
|||
Mean proportion of trailing zeroes in factorials to 10000 is 0.081267 |
|||
(let? Sock (accept @) |
|||
The mean proportion dips permanently below 0.07 at 31549. (0.1s) |
|||
(unless (fork) # Handle request in child process |
|||
</pre> |
|||
(in Sock |
|||
(while (rd) # Handle requests |
|||
(out Sock |
|||
(pr (eval @)) ) ) ) # Evaluate and send reply |
|||
(bye) ) # Exit child process |
|||
(close Sock) ) ) # Close socket in parent process</syntaxhighlight> |
|||
===Client=== |
|||
<syntaxhighlight lang="picolisp">(let? Sock (connect "localhost" 12321) |
|||
(out Sock (pr '*Pid)) # Query PID from server |
|||
(println 'PID (in Sock (rd))) # Receive and print reply |
|||
(out Sock (pr '(* 3 4))) # Request some calculation |
|||
(println 'Result (in Sock (rd))) # Print result |
|||
(close Sock) ) # Close connection to server</syntaxhighlight> |
|||
Output: |
|||
<pre>PID 18372 |
|||
Result 12</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
<syntaxhighlight lang="python">def facpropzeros(N, verbose = True): |
|||
{{works with|Python|2.4 and 2.6}} |
|||
proportions = [0.0] * N |
|||
fac, psum = 1, 0.0 |
|||
for i in range(N): |
|||
fac *= i + 1 |
|||
d = list(str(fac)) |
|||
psum += sum(map(lambda x: x == '0', d)) / len(d) |
|||
proportions[i] = psum / (i + 1) |
|||
if verbose: |
|||
=== XML-RPC === |
|||
print("The mean proportion of 0 in factorials from 1 to {} is {}.".format(N, psum / N)) |
|||
'''Protocol:''' XML-RPC |
|||
return proportions |
|||
==== Server ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/env python |
|||
# -*- coding: utf-8 -*- |
|||
import SimpleXMLRPCServer |
|||
for n in [100, 1000, 10000]: |
|||
class MyHandlerInstance: |
|||
facpropzeros(n) |
|||
'''Method for returning data got from client''' |
|||
return 'Server responded: %s' % data |
|||
props = facpropzeros(47500, False) |
|||
def div(self, num1, num2): |
|||
n = (next(i for i in reversed(range(len(props))) if props[i] > 0.16)) |
|||
'''Method for divide 2 numbers''' |
|||
return num1/num2 |
|||
print("The mean proportion dips permanently below 0.16 at {}.".format(n + 2)) |
|||
def foo_function(): |
|||
</syntaxhighlight>{{out}} |
|||
'''A function (not an instance method)''' |
|||
<pre> |
|||
return True |
|||
The mean proportion of 0 in factorials from 1 to 100 is 0.24675318616743216. |
|||
The mean proportion of 0 in factorials from 1 to 1000 is 0.20354455110316458. |
|||
HOST = "localhost" |
|||
The mean proportion of 0 in factorials from 1 to 10000 is 0.17300384824186707. |
|||
PORT = 8000 |
|||
The mean proportion dips permanently below 0.16 at 47332. |
|||
</pre> |
|||
server = SimpleXMLRPCServer.SimpleXMLRPCServer((HOST, PORT)) |
|||
The means can be plotted, showing a jump from 0 to over 0.25, followed by a slowly dropping curve: |
|||
<syntaxhighlight lang="python">import matplotlib.pyplot as plt |
|||
# register built-in system.* functions. |
|||
plt.plot([i+1 for i in range(len(props))], props) |
|||
server.register_introspection_functions() |
|||
# register our instance |
|||
server.register_instance(MyHandlerInstance()) |
|||
# register our function as well |
|||
server.register_function(foo_function) |
|||
try: |
|||
# serve forever |
|||
server.serve_forever() |
|||
except KeyboardInterrupt: |
|||
print 'Exiting...' |
|||
server.server_close()</syntaxhighlight> |
|||
==== Client ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/env python |
|||
# -*- coding: utf-8 -*- |
|||
import xmlrpclib |
|||
HOST = "localhost" |
|||
PORT = 8000 |
|||
rpc = xmlrpclib.ServerProxy("http://%s:%d" % (HOST, PORT)) |
|||
# print what functions does server support |
|||
print 'Server supports these functions:', |
|||
print ' '.join(rpc.system.listMethods()) |
|||
# echo something |
|||
rpc.echo("We sent this data to server") |
|||
# div numbers |
|||
print 'Server says: 8 / 4 is: %d' % rpc.div(8, 4) |
|||
# control if foo_function returns True |
|||
if rpc.foo_function(): |
|||
print 'Server says: foo_function returned True'</syntaxhighlight> |
|||
===HTTP=== |
|||
'''Protocol:''' HTTP |
|||
==== Server ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
import BaseHTTPServer |
|||
HOST = "localhost" |
|||
PORT = 8000 |
|||
# we just want to write own class, we replace do_GET method. This could be extended, I just added basics |
|||
# see; http://docs.python.org/lib/module-BaseHTTPServer.html |
|||
class MyHTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler): |
|||
def do_GET(self): |
|||
# send 200 (OK) message |
|||
self.send_response(200) |
|||
# send header |
|||
self.send_header("Content-type", "text/html") |
|||
self.end_headers() |
|||
# send context |
|||
self.wfile.write("<html><head><title>Our Web Title</title></head>") |
|||
self.wfile.write("<body><p>This is our body. You wanted to visit <b>%s</b> page</p></body>" % self.path) |
|||
self.wfile.write("</html>") |
|||
if __name__ == '__main__': |
|||
server = BaseHTTPServer.HTTPServer((HOST, PORT), MyHTTPHandler) |
|||
try: |
|||
server.serve_forever() |
|||
except KeyboardInterrupt: |
|||
print 'Exiting...' |
|||
server.server_close()</syntaxhighlight> |
|||
==== Client ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
import httplib |
|||
HOST = "localhost" |
|||
PORT = 8000 |
|||
conn = httplib.HTTPConnection(HOST, PORT) |
|||
conn.request("GET", "/somefile") |
|||
response = conn.getresponse() |
|||
print 'Server Status: %d' % response.status |
|||
print 'Server Message: %s' % response.read()</syntaxhighlight> |
|||
===Socket, Pickle format=== |
|||
'''Protocol:''' raw socket / pickle format |
|||
This example builds a very basic RPC mechanism on top of sockets and the [http://docs.python.org/library/pickle.html#module-pickle pickle module]. Please note that the pickle module is not secure - a malicious client can build malformed data to execute arbitrary code on the server. If untrusted clients can access the server, the [http://docs.python.org/library/json.html json module] could be used as a substitute, but we lose the ability to transfer arbitrary Python objects that way. |
|||
==== Server ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
import SocketServer |
|||
import pickle |
|||
HOST = "localhost" |
|||
PORT = 8000 |
|||
class RPCServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): |
|||
# The object_to_proxy member should be set to the object we want |
|||
# methods called on. Unfortunately, we can't do this in the constructor |
|||
# because the constructor should not be overridden in TCPServer... |
|||
daemon_threads = True |
|||
class RPCHandler(SocketServer.StreamRequestHandler): |
|||
def handle(self): |
|||
in_channel = pickle.Unpickler(self.rfile) |
|||
out_channel = pickle.Pickler(self.wfile, protocol=2) |
|||
while True: |
|||
try: |
|||
name, args, kwargs = in_channel.load() |
|||
print 'got %s %s %s' % (name, args, kwargs) |
|||
except EOFError: |
|||
# EOF means we're done with this request. |
|||
# Catching this exception to detect EOF is a bit hackish, |
|||
# but will work for a quick demo like this |
|||
break |
|||
try: |
|||
method = getattr(self.server.object_to_proxy, name) |
|||
result = method(*args, **kwargs) |
|||
except Exception, e: |
|||
out_channel.dump(('Error',e)) |
|||
else: |
|||
out_channel.dump(('OK',result)) |
|||
class MyHandlerInstance(object): |
|||
def echo(self, data): |
|||
'''Method for returning data got from client''' |
|||
return 'Server responded: %s' % data |
|||
def div(self, dividend, divisor): |
|||
'''Method to divide 2 numbers''' |
|||
return dividend/divisor |
|||
def is_computer_on(self): |
|||
return True |
|||
if __name__ == '__main__': |
|||
rpcserver = RPCServer((HOST, PORT), RPCHandler) |
|||
rpcserver.object_to_proxy = MyHandlerInstance() |
|||
try: |
|||
rpcserver.serve_forever() |
|||
except KeyboardInterrupt: |
|||
print 'Exiting...' |
|||
rpcserver.server_close() |
|||
</syntaxhighlight> |
</syntaxhighlight> |
||
=== Base 1000 version === |
|||
{{trans|Go via Phix via Pascal}} |
|||
<syntaxhighlight lang="python">def zinit(): |
|||
zc = [0] * 999 |
|||
for x in range(1, 10): |
|||
zc[x - 1] = 2 # 00x |
|||
zc[10 * x - 1] = 2 # 0x0 |
|||
zc[100 * x - 1] = 2 # x00 |
|||
for y in range(10, 100, 10): |
|||
zc[y + x - 1] = 1 # 0yx |
|||
zc[10 * y + x - 1] = 1 # y0x |
|||
zc[10 * (y + x) - 1] = 1 # yx0 |
|||
return zc |
|||
==== Client ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
import socket |
|||
import pickle |
|||
HOST = "localhost" |
|||
PORT = 8000 |
|||
class RPCClient(object): |
|||
def __init__(self, host, port): |
|||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|||
self.socket.connect((host, port)) |
|||
self.rfile = self.socket.makefile('rb') |
|||
self.wfile = self.socket.makefile('wb') |
|||
self.in_channel = pickle.Unpickler(self.rfile) |
|||
self.out_channel = pickle.Pickler(self.wfile, protocol=2) |
|||
def meanfactorialdigits(): |
|||
zc = zinit() |
|||
rfs = [1] |
|||
self.rfile.close() |
|||
total, trail, first = 0.0, 1, 0 |
|||
for f in range(2, 50000): |
|||
carry, d999, zeroes = 0, 0, (trail - 1) * 3 |
|||
j, l = trail, len(rfs) |
|||
while j <= l or carry != 0: |
|||
if j <= l: |
|||
carry = rfs[j-1] * f + carry |
|||
d999 = carry % 1000 |
|||
# Make calling remote methods easy by overriding attribute access. |
|||
if j <= l: |
|||
# Accessing any attribute on our instances will give a proxy method that |
|||
rfs[j-1] = d999 |
|||
def __getattr__(self, name): |
|||
def proxy(*args, **kwargs): |
|||
self.out_channel.dump((name, args, kwargs)) |
|||
self.wfile.flush() # to make sure the server won't wait forever |
|||
status, result = self.in_channel.load() |
|||
if status == 'OK': |
|||
return result |
|||
else: |
else: |
||
rfs.append(d999) |
|||
zeroes += 3 if d999 == 0 else zc[d999-1] |
|||
return proxy |
|||
carry //= 1000 |
|||
j += 1 |
|||
if __name__ == '__main__': |
|||
# connect to server and send data |
|||
rpcclient = RPCClient(HOST, PORT) |
|||
while rfs[trail-1] == 0: |
|||
print 'Testing the echo() method:' |
|||
trail += 1 |
|||
print rpcclient.echo('Hello world!') |
|||
print |
|||
print 'Calculating 42/2 on the remote machine:' |
|||
print rpcclient.div(42, 2) |
|||
print |
|||
print 'is_computer_on on the remote machine returns:' |
|||
print rpcclient.is_computer_on() |
|||
print |
|||
print 'Testing keyword args:' |
|||
print '42/2 is:', rpcclient.div(divisor=2, dividend=42) |
|||
rpcclient._close() |
|||
del rpcclient</syntaxhighlight> |
|||
# d999 is a quick correction for length and zeros |
|||
===Pyro=== |
|||
d999 = rfs[-1] |
|||
'''Note:''' You should install Pyro (http://pyro.sourceforge.net) first and run '''pyro-ns''' binary to run code below. |
|||
d999 = 0 if d999 >= 100 else 2 if d999 < 10 else 1 |
|||
zeroes -= d999 |
|||
==== Server ==== |
|||
digits = len(rfs) * 3 - d999 |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
total += zeroes / digits |
|||
# -*- coding: utf-8 -*- |
|||
ratio = total / f |
|||
if f in [100, 1000, 10000]: |
|||
print("The mean proportion of zero digits in factorials to {} is {}".format(f, ratio)) |
|||
if ratio >= 0.16: |
|||
first = 0 |
|||
elif first == 0: |
|||
first = f |
|||
print("The mean proportion dips permanently below 0.16 at {}.".format(first)) |
|||
import Pyro.core |
|||
import Pyro.naming |
|||
# create instance that will return upper case |
|||
class StringInstance(Pyro.core.ObjBase): |
|||
def makeUpper(self, data): |
|||
return data.upper() |
|||
class MathInstance(Pyro.core.ObjBase): |
|||
def div(self, num1, num2): |
|||
return num1/num2 |
|||
import time |
|||
if __name__ == '__main__': |
|||
TIME0 = time.perf_counter() |
|||
server = Pyro.core.Daemon() |
|||
meanfactorialdigits() |
|||
name_server = Pyro.naming.NameServerLocator().getNS() |
|||
print("\nTotal time:", time.perf_counter() - TIME0, "seconds.") |
|||
server.useNameServer(name_server) |
|||
</syntaxhighlight>{{out}} |
|||
server.connect(StringInstance(), 'string') |
|||
<pre> |
|||
server.connect(MathInstance(), 'math') |
|||
The mean proportion of zero digits in factorials to 100 is 0.24675318616743216 |
|||
try: |
|||
The mean proportion of zero digits in factorials to 1000 is 0.20354455110316458 |
|||
server.requestLoop() |
|||
The mean proportion of zero digits in factorials to 10000 is 0.17300384824186707 |
|||
except KeyboardInterrupt: |
|||
The mean proportion dips permanently below 0.16 at 47332. |
|||
print 'Exiting...' |
|||
server.shutdown()</syntaxhighlight> |
|||
==== Client ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
import Pyro.core |
|||
DATA = "my name is eren" |
|||
NUM1 = 10 |
|||
NUM2 = 5 |
|||
string = Pyro.core.getProxyForURI("PYRONAME://string") |
|||
math = Pyro.core.getProxyForURI("PYRONAME://math") |
|||
print 'We sent: %s' % DATA |
|||
print 'Server responded: %s\n' % string.makeUpper(DATA) |
|||
print 'We sent two numbers to divide: %d and %d' % (NUM1, NUM2) |
|||
print 'Server responded the result: %s' % math.div(NUM1, NUM2)</syntaxhighlight> |
|||
=== Spread === |
|||
'''Note:''' You should install Spread (http://www.spread.org) and its python bindings (http://www.python.org/other/spread/) |
|||
==== Server ==== |
|||
You don't need any code for server. You should start "spread" daemon by typing "spread -c /etc/spread.conf -n localhost". If you want more configuration, look at /etc/spread.conf. |
|||
After starting daemon, if you want to make sure that it is running, enter '''spuser -s 4803''' command where 4803 is your port set in spread.conf, you will see prompt, type '''j user''', you should see something like this message: ''Received REGULAR membership for group test with 3 members, where I am member 2'' |
|||
==== Client (Listener) ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
import spread |
|||
PORT = '4803' |
|||
# connect spread daemon |
|||
conn = spread.connect(PORT) |
|||
# join the room |
|||
conn.join('test') |
|||
print 'Waiting for messages... If you want to stop this script, please stop spread daemon' |
|||
while True: |
|||
recv = conn.receive() |
|||
if hasattr(recv, 'sender') and hasattr(recv, 'message'): |
|||
print 'Sender: %s' % recv.sender |
|||
print 'Message: %s' % recv.message</syntaxhighlight> |
|||
==== Client (Sender) ==== |
|||
<syntaxhighlight lang="python">#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
import spread |
|||
PORT = '4803' |
|||
conn = spread.connect(PORT) |
|||
conn.join('test') |
|||
conn.multicast(spread.RELIABLE_MESS, 'test', 'hello, this is message sent from python') |
|||
conn.disconnect()</syntaxhighlight> |
|||
=={{header|Racket}}== |
|||
Server and client in the same piece of code, running a useless (fib 42) computation, four times, on four hosts (which all happen to be "localhost", but that can change, of course). |
|||
<syntaxhighlight lang="racket"> |
|||
#lang racket/base |
|||
(require racket/place/distributed racket/place) |
|||
(define (fib n) |
|||
(if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2))))) |
|||
(provide work) |
|||
(define (work) |
|||
(place ch |
|||
(place-channel-put ch (fib (place-channel-get ch))))) |
|||
(module+ main |
|||
(define places |
|||
(for/list ([host '("localhost" "localhost" "localhost" "localhost")] |
|||
[port (in-naturals 12345)]) |
|||
(define-values [node place] |
|||
(spawn-node-supervise-place-at host #:listen-port port #:thunk #t |
|||
(quote-module-path "..") 'work)) |
|||
place)) |
|||
(message-router |
|||
(after-seconds 1 |
|||
(for ([p places]) (*channel-put p 42)) |
|||
(printf "Results: ~s\n" (map *channel-get places)) |
|||
(exit)))) |
|||
</syntaxhighlight> |
|||
Total time: 648.3583232999999 seconds. |
|||
</pre> |
|||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
Works, but depressingly slow for 10000. |
|||
(formerly Perl 6) |
|||
<syntaxhighlight lang="raku" line>sub postfix:<!> (Int $n) { ( constant factorial = 1, 1, |[\*] 2..* )[$n] } |
|||
Server listens for JSON encoded messages. It processes requests for set|get|dump. 'set' stores a message, 'get' returns message, 'dump' returns all stored messages. Optional parameters for ip address and port. |
|||
sink 10000!; # prime the iterator to allow multithreading |
|||
sub zs ($n) { ( constant zero-share = (^Inf).race(:32batch).map: { (.!.comb.Bag){'0'} / .!.chars } )[$n+1] } |
|||
Server.raku: |
|||
<pre>./server.raku --usage |
|||
Usage: |
|||
server.p6 [--server=<Any>] [--port=<Any>]</pre> |
|||
<syntaxhighlight lang="raku" line>#!/usr/bin/env raku |
|||
use JSON::Fast ; |
|||
sub MAIN( :$server='0.0.0.0' , :$port=3333 ) { |
|||
my %db ; |
|||
react { |
|||
whenever IO::Socket::Async.listen( $server , $port ) -> $conn { |
|||
whenever $conn.Supply.lines -> $line { |
|||
my %response = 'status' => '' ; |
|||
my $msg = from-json $line ; |
|||
say $msg.raku; |
|||
given $msg{"function"} { |
|||
when 'set' { |
|||
%db{ $msg<topic> } = $msg<message> ; |
|||
%response<status> = 'ok' ; |
|||
} |
|||
when 'get' { |
|||
%response<topic> = $msg<topic> ; |
|||
%response<message> = %db{ $msg<topic> } ; |
|||
%response<status> = 'ok' ; |
|||
} |
|||
when 'dump' { |
|||
%response = %db ; |
|||
} |
|||
when 'delete' { |
|||
%db{ $msg<topic> }:delete; |
|||
%response<status> = 'ok' ; |
|||
} |
|||
} |
|||
$conn.print( to-json(%response, :!pretty) ~ "\n" ) ; |
|||
LAST { $conn.close ; } |
|||
QUIT { default { $conn.close ; say "oh no, $_";}} |
|||
CATCH { default { say .^name, ': ', .Str , " handled in $?LINE";}} |
|||
} |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
client.raku: |
|||
<pre>Usage: |
|||
client.raku [--server=<Any>] [--port=<Any>] [--json=<Any>] set <topic> [<message>] |
|||
client.raku [--server=<Any>] [--port=<Any>] get <topic> |
|||
client.raku [--server=<Any>] [--port=<Any>] dump</pre> |
|||
<syntaxhighlight lang="raku" line>#!/usr/bin/env raku |
|||
use JSON::Fast ; |
|||
multi MAIN('set', $topic, $message='', :$server='localhost', :$port='3333', :$json='') { |
|||
my %msg = function => 'set' , topic=> $topic , message=> $message ; |
|||
%msg{"message"} = from-json( $json ) if $json ; |
|||
sendmsg( %msg , $server, $port) ; |
|||
} |
|||
multi MAIN('get', $topic, :$server='localhost', :$port='3333') { |
|||
my %msg = function => 'get' , topic=> $topic ; |
|||
sendmsg( %msg , $server, $port) ; |
|||
} |
|||
multi MAIN('delete', $topic, :$server='localhost', :$port='3333') { |
|||
my %msg = function => 'delete' , topic=> $topic ; |
|||
sendmsg( %msg , $server, $port) ; |
|||
} |
|||
multi MAIN('dump', :$server='localhost', :$port='3333') { |
|||
my %msg = function => 'dump' ; |
|||
sendmsg( %msg , $server, $port) ; |
|||
} |
|||
sub sendmsg( %msg , $server, $port){ |
|||
my $conn = await IO::Socket::Async.connect( $server , $port ); |
|||
$conn.print: to-json( %msg,:!pretty)~"\n"; |
|||
react { |
|||
whenever $conn.Supply -> $data { |
|||
print $data; |
|||
$conn.close; |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
examples: |
|||
<pre>echo '{"function":"set","topic":"push","message":["perl5","raku","rakudo"]}' | nc localhost 3333 |
|||
.say for ( |
|||
./client.raku set version raku |
|||
100 |
|||
{"status": "ok"} |
|||
,1000 |
|||
./client.raku get version |
|||
,10000 |
|||
{"status": "ok","topic": "version","message": "raku"} |
|||
).map: -> \n { "{n}: {([+] (^n).map: *.&zs) / n}" }</syntaxhighlight> |
|||
./client.raku --json='["one","two","three"]' set mylist |
|||
{{out}} |
|||
{"status": "ok"} |
|||
<pre>100: 0.24675318616743216 |
|||
./client.raku dump |
|||
1000: 0.20354455110316458 |
|||
{"push": ["perl5","raku","rakudo"],"version": "raku","mylist": ["one","two","three"]} |
|||
10000: 0.17300384824186605 |
|||
./client.raku delete version |
|||
</pre> |
|||
{"status": "ok"} |
|||
=={{header|REXX}}== |
|||
<syntaxhighlight lang="rexx">/*REXX program computes the mean of the proportion of "0" digits a series of factorials.*/ |
|||
parse arg $ /*obtain optional arguments from the CL*/ |
|||
if $='' | $="," then $= 100 1000 10000 /*not specified? Then use the default.*/ |
|||
#= words($) /*the number of ranges to be used here.*/ |
|||
numeric digits 100 /*increase dec. digs, but only to 100. */ |
|||
big= word($, #); != 1 /*obtain the largest number in ranges. */ |
|||
do i=1 for big /*calculate biggest ! using 100 digs.*/ |
|||
!= ! * i /*calculate the factorial of BIG. */ |
|||
end /*i*/ |
|||
if pos('E', !)>0 then do /*In exponential format? Then get EXP.*/ |
|||
parse var ! 'E' x /*parse the exponent from the number. */ |
|||
numeric digits x+1 /*set the decimal digits to X plus 1.*/ |
|||
end /* [↑] the +1 is for the dec. point.*/ |
|||
title= ' mean proportion of zeros in the (decimal) factorial products for N' |
|||
server output: |
|||
say ' N │'center(title, 80) /*display the title for the output. */ |
|||
${:function("set"), :message($["perl5", "raku", "rakudo"]), :topic("push")} |
|||
say '───────────┼'center("" , 80, '─') /* " a sep " " " */ |
|||
${:function("set"), :message("raku"), :topic("version")} |
|||
${:function("get"), :topic("version")} |
|||
${:function("set"), :message($["one", "two", "three"]), :topic("mylist")} |
|||
${:function("dump")} |
|||
${:function("delete"), :topic("version")}</pre> |
|||
do j=1 for #; n= word($, j) /*calculate some factorial ranges. */ |
|||
=={{header|Ruby}}== |
|||
say center( commas(n), 11)'│' left(0dist(n), 75)... /*show results for above range.*/ |
|||
Uses the distributed Ruby (dRuby) from the standard library. The "druby:" protocol uses TCP/IP sockets for communication. |
|||
end /*j*/ |
|||
say '───────────┴'center("" , 80, '─') /*display a foot sep for the output. */ |
|||
'''Server''' |
|||
exit 0 /*stick a fork in it, we're all done. */ |
|||
<syntaxhighlight lang="ruby">require 'drb/drb' |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
commas: parse arg ?; do jc=length(?)-3 to 1 by -3; ?=insert(',', ?, jc); end; return ? |
|||
# The URI for the server to connect to |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
URI="druby://localhost:8787" |
|||
0dist: procedure; parse arg z; != 1; y= 0 |
|||
do k=1 for z; != ! * k; y= y + countstr(0, !) / length(!) |
|||
class TimeServer |
|||
end /*k*/ |
|||
return y/z</syntaxhighlight> |
|||
def get_current_time |
|||
{{out|output|text= when using the default inputs:}} |
|||
return Time.now |
|||
<pre> |
|||
end |
|||
N │ mean proportion of zeros in the (decimal) factorial products for N |
|||
───────────┼──────────────────────────────────────────────────────────────────────────────── |
|||
end |
|||
100 │ 0.2467531861674322177784158871973526991129407033266153063813195937196095976... |
|||
1,000 │ 0.2035445511031646356400438031711455302985741167890402203486699704599684047... |
|||
# The object that handles requests on the server |
|||
10,000 │ 0.1730038482418660531800366428930706156810278809057883361518852958446868172... |
|||
FRONT_OBJECT = TimeServer.new |
|||
───────────┴──────────────────────────────────────────────────────────────────────────────── |
|||
</pre> |
|||
$SAFE = 1 # disable eval() and friends |
|||
=={{header|Rust}}== |
|||
{{trans|Phix}} |
|||
DRb.start_service(URI, FRONT_OBJECT) |
|||
<syntaxhighlight lang="rust">fn init_zc() -> Vec<usize> { |
|||
# Wait for the drb server thread to finish before exiting. |
|||
let mut zc = vec![0; 1000]; |
|||
DRb.thread.join</syntaxhighlight> |
|||
zc[0] = 3; |
|||
for x in 1..=9 { |
|||
'''Client''' |
|||
zc[x] = 2; |
|||
<syntaxhighlight lang="ruby">require 'drb/drb' |
|||
zc[10 * x] = 2; |
|||
zc[100 * x] = 2; |
|||
# The URI to connect to |
|||
let mut y = 10; |
|||
SERVER_URI = "druby://localhost:8787" |
|||
while y <= 90 { |
|||
zc[y + x] = 1; |
|||
# Start a local DRbServer to handle callbacks. |
|||
zc[10 * y + x] = 1; |
|||
# |
|||
zc[10 * (y + x)] = 1; |
|||
# Not necessary for this small example, but will be required |
|||
y += 10; |
|||
# as soon as we pass a non-marshallable object as an argument |
|||
# to a dRuby call. |
|||
DRb.start_service |
|||
timeserver = DRbObject.new_with_uri(SERVER_URI) |
|||
puts timeserver.get_current_time</syntaxhighlight> |
|||
=={{header|Tcl}}== |
|||
A rudimentary IRC Server |
|||
<syntaxhighlight lang="tcl">proc main {} { |
|||
global connections |
|||
set connections [dict create] |
|||
socket -server handleConnection 12345 |
|||
vwait dummyVar ;# enter the event loop |
|||
} |
|||
proc handleConnection {channel clientaddr clientport} { |
|||
global connections |
|||
dict set connections $channel address "$clientaddr:$clientport" |
|||
fconfigure $channel -buffering line |
|||
fileevent $channel readable [list handleMessage $channel] |
|||
} |
|||
proc handleMessage {channel} { |
|||
global connections |
|||
if {[gets $channel line] == -1} { |
|||
disconnect $channel |
|||
} else { |
|||
if {[string index [string trimleft $line] 0] eq "/"} { |
|||
set words [lassign [split [string trim $line]] command] |
|||
handleCommand $command $words $channel |
|||
} else { |
|||
echo $line $channel |
|||
} |
} |
||
} |
} |
||
zc |
|||
} |
} |
||
fn main() { |
|||
proc disconnect {channel} { |
|||
use std::time::Instant; |
|||
global connections |
|||
let zc = init_zc(); |
|||
dict unset connections $channel |
|||
let t0 = Instant::now(); |
|||
fileevent $channel readable "" |
|||
let mut trail = 1; |
|||
let mut first = 0; |
|||
} |
|||
let mut total: f64 = 0.0; |
|||
let mut rfs = vec![1]; |
|||
for f in 2..=50000 { |
|||
proc handleCommand {command words channel} { |
|||
let mut carry = 0; |
|||
global connections |
|||
let mut d999: usize; |
|||
switch -exact -- [string tolower $command] { |
|||
let mut zeroes = (trail - 1) * 3; |
|||
let len = rfs.len(); |
|||
dict set connections $channel nick [lindex $words 0] |
|||
let mut j = trail - 1; |
|||
while j < len || carry != 0 { |
|||
if j < len { |
|||
carry += rfs[j] * f; |
|||
} |
|||
d999 = carry % 1000; |
|||
if j < len { |
|||
rfs[j] = d999; |
|||
} else { |
|||
rfs.push(d999); |
|||
} |
|||
zeroes += zc[d999]; |
|||
carry /= 1000; |
|||
j += 1; |
|||
} |
} |
||
while rfs[trail - 1] == 0 { |
|||
trail += 1; |
|||
disconnect $channel |
|||
} |
} |
||
d999 = rfs[rfs.len() - 1]; |
|||
d999 = if d999 < 100 { |
|||
if d999 < 10 { |
|||
2 |
|||
} else { |
|||
1 |
|||
} |
|||
} else { |
|||
0 |
|||
}; |
|||
zeroes -= d999; |
|||
let digits = rfs.len() * 3 - d999; |
|||
total += (zeroes as f64) / (digits as f64); |
|||
let ratio = total / (f as f64); |
|||
if ratio >= 0.16 { |
|||
first = 0; |
|||
} else if first == 0 { |
|||
first = f; |
|||
} |
} |
||
if f == 100 || f == 1000 || f == 10000 { |
|||
} |
|||
let duration = t0.elapsed(); |
|||
} |
|||
println!( |
|||
"Mean proportion of zero digits in factorials to {} is {:.10}. ({}ms)", |
|||
proc echo {message senderchannel} { |
|||
f, |
|||
ratio, |
|||
foreach channel [dict keys $connections] { |
|||
duration.as_millis() |
|||
if {$channel ne $senderchannel} { |
|||
); |
|||
set time [clock format [clock seconds] -format "%T"] |
|||
set nick [dict get $connections $channel nick] |
|||
puts $channel [format "\[%s\] %s: %s" $time $nick $message] |
|||
} |
} |
||
} |
} |
||
let duration = t0.elapsed(); |
|||
} |
|||
println!( |
|||
"The mean proportion dips permanently below 0.16 at {}. ({}ms)", |
|||
first, |
|||
duration.as_millis() |
|||
); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
main</syntaxhighlight> |
|||
<pre> |
|||
Client |
|||
Mean proportion of zero digits in factorials to 100 is 0.2467531862. (0ms) |
|||
<syntaxhighlight lang="tcl">proc main {} { |
|||
Mean proportion of zero digits in factorials to 1000 is 0.2035445511. (1ms) |
|||
global argv argc |
|||
Mean proportion of zero digits in factorials to 10000 is 0.1730038482. (149ms) |
|||
if {$argc != 2} { |
|||
The mean proportion dips permanently below 0.16 at 47332. (4485ms) |
|||
error "usage: [info script] serveraddress serverport" |
|||
</pre> |
|||
} |
|||
=={{header|Ruby}}== |
|||
connect {*}$argv |
|||
<syntaxhighlight lang="ruby">[100, 1000, 10_000].each do |n| |
|||
vwait dummyVar |
|||
v = 1 |
|||
} |
|||
total_proportion = (1..n).sum do |k| |
|||
v *= k |
|||
digits = v.digits |
|||
Rational(digits.count(0), digits.size) |
|||
end |
|||
puts "The mean proportion of 0 in factorials from 1 to #{n} is #{(total_proportion/n).to_f}." |
|||
end</syntaxhighlight> |
|||
{{out}} |
|||
<pre>The mean proportion of 0 in factorials from 1 to 100 is 0.24675318616743222. |
|||
The mean proportion of 0 in factorials from 1 to 1000 is 0.20354455110316463. |
|||
The mean proportion of 0 in factorials from 1 to 10000 is 0.17300384824186604. |
|||
</pre> |
|||
=={{header|Sidef}}== |
|||
<syntaxhighlight lang="ruby">func mean_factorial_digits(n, d = 0) { |
|||
var v = 1 |
|||
proc connect {addr port} { |
|||
var total = 0.float |
|||
global sock |
|||
set sock [socket $addr $port] |
|||
fconfigure $sock -buffering line |
|||
fileevent $sock readable getFromServer |
|||
fileevent stdin readable sendToServer |
|||
} |
|||
for k in (1..n) { |
|||
proc getFromServer {} { |
|||
v *= k |
|||
total += v.digits.count(d)/v.len |
|||
if {[gets $sock line] == -1} { |
|||
puts "disconnected..." |
|||
exit |
|||
} else { |
|||
puts $line |
|||
} |
} |
||
} |
|||
total / n |
|||
proc sendToServer {} { |
|||
global sock |
|||
set msg [string trim [gets stdin]] |
|||
if {[string length $msg] > 0} { |
|||
puts $sock $msg |
|||
} |
|||
} |
} |
||
say mean_factorial_digits(100) |
|||
main</syntaxhighlight> |
|||
say mean_factorial_digits(1000) |
|||
say mean_factorial_digits(10000)</syntaxhighlight> |
|||
=={{header|UnixPipes}}== |
|||
{{ |
{{out}} |
||
<pre> |
|||
Uses netcat and a buffer to cycle the server shell's stdout back to netcat's stdin. |
|||
0.246753186167432217778415887197352699112940703327 |
|||
0.203544551103164635640043803171145530298574116789 |
|||
===Server=== |
|||
0.173003848241866053180036642893070615681027880906 |
|||
{{alertbox|yellow|'''Security risk!''' Anything, able to reach 127.0.0.1 port 1234, can run shell commands as the user who runs the server. This allows other users to gain privileges.}} |
|||
</pre> |
|||
<syntaxhighlight lang="bash">: >/tmp/buffer |
|||
tail -f /tmp/buffer | nc -l 127.0.0.1 1234 | sh >/tmp/buffer 2>&1</syntaxhighlight> |
|||
Limitations: |
|||
* The server can accept only one connection (but continues to run, not exit, after this connection dies). |
|||
* With some systems, <code>tail -f</code> might be slow to notice changes to /tmp/buffer. |
|||
===Client=== |
|||
<syntaxhighlight lang="bash">nc 127.0.0.1 1234</syntaxhighlight> |
|||
Now you can enter commands in the client terminal and get the output back through the same connection. |
|||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
===Brute force=== |
|||
{{trans|Go}} |
|||
{{libheader| |
{{libheader|Wren-big}} |
||
{{libheader|Wren-fmt}} |
{{libheader|Wren-fmt}} |
||
Very slow indeed, 10.75 minutes to reach N = 10,000. |
|||
As Wren has no networking support at present, we use embedded programs for both the server and client with a Go host using the net/rpc package in its standard library. |
|||
<syntaxhighlight lang="wren">import "./big" for BigInt |
|||
import "./fmt" for Fmt |
|||
var fact = BigInt.one |
|||
Moreover, as Wren's VM is not re-entrant, we need to run two VMs from the server side, one to call Go from Wren and the other to call Wren from Go. |
|||
var sum = 0 |
|||
System.print("The mean proportion of zero digits in factorials up to the following are:") |
|||
'''Server:''' |
|||
for (n in 1..10000) { |
|||
<br> |
|||
fact = fact * n |
|||
We need two Wren scripts one for each VM: |
|||
var bytes = fact.toString.bytes |
|||
<syntaxhighlight lang="ecmascript">/* distributed_programming_server.wren */ |
|||
var digits = bytes.count |
|||
var zeros = bytes.count { |b| b == 48 } |
|||
class Rpc { |
|||
sum = sum + zeros / digits |
|||
foreign static register() |
|||
if (n == 100 || n == 1000 || n == 10000) { |
|||
Fmt.print("$,6d = $12.10f", n, sum / n) |
|||
foreign static handleHTTP() |
|||
} |
|||
foreign class Listener { |
|||
construct listen(network, address) {} |
|||
} |
|||
class HTTP { |
|||
foreign static serve(listener) |
|||
} |
|||
Rpc.register() |
|||
Rpc.handleHTTP() |
|||
var listener = Listener.listen("tcp", ":1234") |
|||
HTTP.serve(listener)</syntaxhighlight> |
|||
<br> |
|||
<syntaxhighlight lang="ecmascript">/* distributed_programming_server2.wren */ |
|||
class TaxComputer { |
|||
static tax(amount, rate) { |
|||
if (amount < 0) Fiber.abort("Negative values not allowed.") |
|||
return amount * rate |
|||
} |
} |
||
}</syntaxhighlight> |
}</syntaxhighlight> |
||
{{out}} |
|||
<pre> |
|||
The mean proportion of zero digits in factorials up to the following are: |
|||
100 = 0.2467531862 |
|||
1,000 = 0.2035445511 |
|||
10,000 = 0.1730038482 |
|||
</pre> |
|||
<br> |
<br> |
||
==='String math' and base 1000=== |
|||
We now embed these scripts in the following Go program and run it on one terminal. |
|||
{{trans|Phix}} |
|||
<syntaxhighlight lang="go">/* go run distributed_programming_server.go */ |
|||
Around 60 times faster than before with 10,000 now being reached in about 10.5 seconds. Even the stretch goal is now viable and comes in at 5 minutes 41 seconds. |
|||
<syntaxhighlight lang="wren">import "./fmt" for Fmt |
|||
var rfs = [1] // reverse factorial(1) in base 1000 |
|||
package main |
|||
var init = Fn.new { |zc| |
|||
import( |
|||
for (x in 1..9) { |
|||
wren "github.com/crazyinfin8/WrenGo" |
|||
zc[x-1] = 2 // 00x |
|||
"log" |
|||
zc[10*x - 1] = 2 // 0x0 |
|||
"net" |
|||
zc[100*x - 1] = 2 // x00 |
|||
"net/http" |
|||
var y = 10 |
|||
while (y <= 90) { |
|||
) |
|||
zc[y + x - 1] = 1 // 0yx |
|||
zc[10*y + x - 1] = 1 // y0x |
|||
type any = interface{} |
|||
zc[10*(y + x) - 1] = 1 // yx0 |
|||
y = y + 10 |
|||
type TaxComputer float64 |
|||
} |
|||
var vm2 *wren.VM |
|||
var fileName = "distributed_programming_server.wren" |
|||
var fileName2 = "distributed_programming_server2.wren" |
|||
func (taxRate TaxComputer) Tax(x float64, r *float64) error { |
|||
wrenVar, _ := vm2.GetVariable(fileName2, "TaxComputer") |
|||
wrenClass, _ := wrenVar.(*wren.Handle) |
|||
defer wrenClass.Free() |
|||
wrenMethod, _ := wrenClass.Func("tax(_,_)") |
|||
defer wrenMethod.Free() |
|||
ret, _ := wrenMethod.Call(x, float64(taxRate)) |
|||
*r = ret.(float64) |
|||
return nil |
|||
} |
|||
func register(vm *wren.VM, parameters []any) (any, error) { |
|||
c := TaxComputer(0.05) // 5% tax rate |
|||
rpc.Register(c) |
|||
return nil, nil |
|||
} |
|||
func handleHTTP(vm *wren.VM, parameters []any) (any, error) { |
|||
rpc.HandleHTTP() |
|||
return nil, nil |
|||
} |
|||
func serve(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[1].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
listener := ifc.(*net.Listener) |
|||
http.Serve(*listener, nil) |
|||
return nil, nil |
|||
} |
|||
func listen(vm *wren.VM, parameters []any) (any, error) { |
|||
network := parameters[1].(string) |
|||
address := parameters[2].(string) |
|||
listener, err := net.Listen(network, address) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
} |
||
return &listener, nil |
|||
} |
} |
||
var zc = List.filled(999, 0) |
|||
func main() { |
|||
init.call(zc) |
|||
vm := wren.NewVM() |
|||
var total = 0 |
|||
vm2 = wren.NewVM() |
|||
var trail = 1 |
|||
vm2.InterpretFile(fileName2) |
|||
var first = 0 |
|||
var firstRatio = 0 |
|||
rpcMethodMap := wren.MethodMap { |
|||
System.print("The mean proportion of zero digits in factorials up to the following are:") |
|||
"static register()": register, |
|||
for (f in 2..50000) { |
|||
"static handleHTTP()": handleHTTP, |
|||
var carry = 0 |
|||
var d999 = 0 |
|||
var zeros = (trail-1) * 3 |
|||
var j = trail |
|||
var l = rfs.count |
|||
while (j <= l || carry != 0) { |
|||
if (j <= l) carry = rfs[j-1]*f + carry |
|||
d999 = carry % 1000 |
|||
if (j <= l) { |
|||
rfs[j-1] = d999 |
|||
} else { |
|||
rfs.add(d999) |
|||
} |
|||
zeros = zeros + ((d999 == 0) ? 3 : zc[d999-1]) |
|||
carry = (carry/1000).floor |
|||
j = j + 1 |
|||
} |
} |
||
while (rfs[trail-1] == 0) trail = trail + 1 |
|||
// d999 = quick correction for length and zeros |
|||
httpMethodMap := wren.MethodMap { "static serve(_)":serve } |
|||
d999 = rfs[-1] |
|||
d999 = (d999 < 100) ? ((d999 < 10) ? 2 : 1) : 0 |
|||
classMap := wren.ClassMap { |
|||
zeros = zeros - d999 |
|||
"Listener": wren.NewClass(listen, nil, nil), |
|||
var digits = rfs.count * 3 - d999 |
|||
"Rpc" : wren.NewClass(nil, nil, rpcMethodMap), |
|||
total = total + zeros/digits |
|||
"HTTP" : wren.NewClass(nil, nil, httpMethodMap), |
|||
var ratio = total / f |
|||
if (ratio >= 0.16) { |
|||
first = 0 |
|||
firstRatio = 0 |
|||
} else if (first == 0) { |
|||
first = f |
|||
firstRatio = ratio |
|||
} |
} |
||
if (f == 100 || f == 1000 || f == 10000) { |
|||
Fmt.print("$,6d = $12.10f", f, ratio) |
|||
module := wren.NewModule(classMap) |
|||
vm.SetModule(fileName, module) |
|||
vm.InterpretFile(fileName) |
|||
vm.Free() |
|||
vm2.Free() |
|||
}</syntaxhighlight> |
|||
<br> |
|||
'''Client:''' |
|||
<br> |
|||
Just one Wren script needed here: |
|||
<syntaxhighlight lang="ecmascript">/* distributed_programming_client.wren */ |
|||
import "./fmt" for Fmt |
|||
foreign class Client { |
|||
construct dialHTTP(network, address) {} |
|||
foreign call(serviceMethod, arg) |
|||
} |
|||
var client = Client.dialHTTP("tcp", "localhost:1234") |
|||
var amounts = [3, 5.6] |
|||
for (amount in amounts) { |
|||
var tax = client.call("TaxComputer.Tax", amount) |
|||
Fmt.print("Tax on $0.2f = $0.2f", amount, tax) |
|||
}</syntaxhighlight> |
|||
<br> |
|||
which we embed in the following Go program and run it on a different terminal. |
|||
<syntaxhighlight lang="go">/* go run distributed_programming_client.go */ |
|||
package main |
|||
import( |
|||
wren "github.com/crazyinfin8/WrenGo" |
|||
"log" |
|||
"net/rpc" |
|||
"strings" |
|||
) |
|||
type any = interface{} |
|||
func dialHTTP(vm *wren.VM, parameters []any) (any, error) { |
|||
network := parameters[1].(string) |
|||
address := parameters[2].(string) |
|||
client, err := rpc.DialHTTP(network, address) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
} |
||
return &client, nil |
|||
} |
} |
||
Fmt.write("$,6d = $12.10f", first, firstRatio) |
|||
System.print(" (stays below 0.16 after this)") |
|||
func call(vm *wren.VM, parameters []any) (any, error) { |
|||
Fmt.print("$,6d = $12.10f", 50000, total/50000)</syntaxhighlight> |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
client := ifc.(**rpc.Client) |
|||
serviceMethod := parameters[1].(string) |
|||
amount := parameters[2].(float64) |
|||
var tax float64 |
|||
err := (*client).Call(serviceMethod, amount, &tax) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
return tax, nil |
|||
} |
|||
func moduleFn(vm *wren.VM, name string) (string, bool) { |
|||
if name != "meta" && name != "random" && !strings.HasSuffix(name, ".wren") { |
|||
name += ".wren" |
|||
} |
|||
return wren.DefaultModuleLoader(vm, name) |
|||
} |
|||
func main() { |
|||
cfg := wren.NewConfig() |
|||
cfg.LoadModuleFn = moduleFn |
|||
vm := cfg.NewVM() |
|||
fileName := "distributed_programming_client.wren" |
|||
clientMethodMap := wren.MethodMap { "call(_,_)": call } |
|||
classMap := wren.ClassMap { "Client": wren.NewClass(dialHTTP, nil, clientMethodMap) } |
|||
module := wren.NewModule(classMap) |
|||
vm.SetModule(fileName, module) |
|||
vm.InterpretFile(fileName) |
|||
vm.Free() |
|||
}</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
Output on the client terminal: |
|||
<pre> |
<pre> |
||
The mean proportion of zero digits in factorials up to the following are: |
|||
Tax on 3.00 = 0.15 |
|||
100 = 0.2467531862 |
|||
1,000 = 0.2035445511 |
|||
10,000 = 0.1730038482 |
|||
47,332 = 0.1599999958 (stays below 0.16 after this) |
|||
50,000 = 0.1596200546 |
|||
</pre> |
</pre> |
||
{{omit from|Lotus 123 Macro Scripting}} |
|||
{{omit from|Maxima}} |
|||
{{omit from|PARI/GP}} |
|||
{{omit from|Retro}} |
Latest revision as of 12:08, 8 February 2024
You are encouraged to solve this task according to the task description, using any language you may know.
Large Factorials and the Distribution of '0' in base 10 digits.
- About the task
We can see that some features of factorial numbers (the series of numbers 1!, 2!, 3!, ...) come about because such numbers are the product of a series of counting numbers, and so those products have predictable factors. For example, all factorials above 1! are even numbers, since they have 2 as a factor. Similarly, all factorials from 5! up end in a 0, because they have 5 and 2 as factors, and thus have 10 as a factor. In fact, the factorial integers add another 0 at the end of the factorial for every step of 5 upward: 5! = 120, 10! = 3628800, 15! = 1307674368000, 16! = 20922789888000 and so on.
Because factorial numbers, which quickly become quite large, continue to have another terminal 0 on the right hand side of the number for every factor of 5 added to the factorial product, one might think that the proportion of zeros in a base 10 factorial number might be close to 1/5. However, though the factorial products add another terminating 0 every factor of 5 multiplied into the product, as the numbers become quite large, the number of digits in the factorial product expands exponentially, and so the number above the terminating zeros tends toward 10% of each digit from 0 to 1 as the factorial becomes larger. Thus, as the factorials become larger, the proportion of 0 digits in the factorial products shifts slowly from around 1/5 toward 1/10, since the number of terminating zeros in n! increases only in proportion to n, whereas the number of digits of n! in base 10 increases exponentially.
- The task
Create a function to calculate the mean of the proportions of 0 digits out of the total digits found in each factorial product from 1! to N!. This proportion of 0 digits in base 10 should be calculated using the number as printed as a base 10 integer.
Example: for 1 to 6 we have 1!, 2!, 3!, 4!, 5!, 6!, or (1, 2, 6, 24, 120, 720), so we need the mean of (0/1, 0/1, 0/1, 0/2, 1/3, 1/3) = (2/3) (totals of each proportion) / 6 (= N), or 0.1111111...
Example: for 1 to 25 the mean of the proportions of 0 digits in the factorial products series of N! with N from 1 to 25 is 0.26787.
Do this task for 1 to N where N is in (100, 1000, and 10000), so, compute the mean of the proportion of 0 digits for each product in the series of each of the factorials from 1 to 100, 1 to 1000, and 1 to 10000.
- Stretch task
Find the N in 10000 < N < 50000 where the mean of the proportions of 0 digits in the factorial products from 1 to N permanently falls below 0.16. This task took many hours in the Python example, though I wonder if there is a faster algorithm out there.
11l
F facpropzeros(n, verbose = 1B)
V proportions = [0.0] * n
V (fac, psum) = (BigInt(1), 0.0)
L(i) 0 .< n
fac *= i + 1
V d = String(fac)
psum += sum(d.map(x -> Int(x == ‘0’))) / Float(d.len)
proportions[i] = psum / (i + 1)
I verbose
print(‘The mean proportion of 0 in factorials from 1 to #. is #..’.format(n, psum / n))
R proportions
L(n) [100, 1000, 10000]
facpropzeros(n)
- Output:
The mean proportion of 0 in factorials from 1 to 100 is 0.246753186. The mean proportion of 0 in factorials from 1 to 1000 is 0.203544551. The mean proportion of 0 in factorials from 1 to 10000 is 0.173003848.
Base 1000 version
F zinit()
V zc = [0] * 999
L(x) 1..9
zc[x - 1] = 2
zc[10 * x - 1] = 2
zc[100 * x - 1] = 2
L(y) (10.<100).step(10)
zc[y + x - 1] = 1
zc[10 * y + x - 1] = 1
zc[10 * (y + x) - 1] = 1
R zc
F meanfactorialdigits()
V zc = zinit()
V rfs = [1]
V (total, trail, first) = (0.0, 1, 0)
L(f) 2 .< 50000
V (carry, d999, zeroes) = (0, 0, (trail - 1) * 3)
V (j, l) = (trail, rfs.len)
L j <= l | carry != 0
I j <= l
carry = rfs[j - 1] * f + carry
d999 = carry % 1000
I j <= l
rfs[j - 1] = d999
E
rfs.append(d999)
zeroes += I d999 == 0 {3} E zc[d999 - 1]
carry I/= 1000
j++
L rfs[trail - 1] == 0
trail++
d999 = rfs.last
d999 = I d999 >= 100 {0} E I d999 < 10 {2} E 1
zeroes -= d999
V digits = rfs.len * 3 - d999
total += Float(zeroes) / digits
V ratio = total / f
I f C [100, 1000, 10000]
print(‘The mean proportion of zero digits in factorials to #. is #.’.format(f, ratio))
I ratio >= 0.16
first = 0
E I first == 0
first = f
print(‘The mean proportion dips permanently below 0.16 at ’first‘.’)
meanfactorialdigits()
- Output:
The mean proportion of zero digits in factorials to 100 is 0.246753186 The mean proportion of zero digits in factorials to 1000 is 0.203544551 The mean proportion of zero digits in factorials to 10000 is 0.173003848 The mean proportion dips permanently below 0.16 at 47332.
Arturo
su: 0.0
f: 1
lim: 100
loop 1..10000 'n [
'f * n
str: to :string f
'su + (enumerate str 'c -> c = `0`) // size str
if n = lim [
print [n ":" su // n]
'lim * 10
]
]
- Output:
100 : 0.2467531861674322 1000 : 0.2035445511031646 10000 : 0.1730038482418671
C#
using System;
using System.Collections.Generic;
using System.Numerics;
public class DistributionInFactorials
{
public static void Main(string[] args)
{
List<int> limits = new List<int> { 100, 1_000, 10_000 };
foreach (int limit in limits)
{
MeanFactorialDigits(limit);
}
}
private static void MeanFactorialDigits(int limit)
{
BigInteger factorial = BigInteger.One;
double proportionSum = 0.0;
double proportionMean = 0.0;
for (int n = 1; n <= limit; n++)
{
factorial = factorial * n;
string factorialString = factorial.ToString();
int digitCount = factorialString.Length;
long zeroCount = factorialString.Split('0').Length - 1;
proportionSum += (double)zeroCount / digitCount;
proportionMean = proportionSum / n;
}
string result = string.Format("{0:F8}", proportionMean);
Console.WriteLine("Mean proportion of zero digits in factorials from 1 to " + limit + " is " + result);
}
}
- Output:
Mean proportion of zero digits in factorials from 1 to 100 is 0.24675319 Mean proportion of zero digits in factorials from 1 to 1000 is 0.20354455 Mean proportion of zero digits in factorials from 1 to 10000 is 0.17300385
C++
#include <array>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <vector>
auto init_zc() {
std::array<int, 1000> zc;
zc.fill(0);
zc[0] = 3;
for (int x = 1; x <= 9; ++x) {
zc[x] = 2;
zc[10 * x] = 2;
zc[100 * x] = 2;
for (int y = 10; y <= 90; y += 10) {
zc[y + x] = 1;
zc[10 * y + x] = 1;
zc[10 * (y + x)] = 1;
}
}
return zc;
}
template <typename clock_type>
auto elapsed(const std::chrono::time_point<clock_type>& t0) {
auto t1 = clock_type::now();
auto duration =
std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
return duration.count();
}
int main() {
auto zc = init_zc();
auto t0 = std::chrono::high_resolution_clock::now();
int trail = 1, first = 0;
double total = 0;
std::vector<int> rfs{1};
std::cout << std::fixed << std::setprecision(10);
for (int f = 2; f <= 50000; ++f) {
int carry = 0, d999, zeroes = (trail - 1) * 3, len = rfs.size();
for (int j = trail - 1; j < len || carry != 0; ++j) {
if (j < len)
carry += rfs[j] * f;
d999 = carry % 1000;
if (j < len)
rfs[j] = d999;
else
rfs.push_back(d999);
zeroes += zc[d999];
carry /= 1000;
}
while (rfs[trail - 1] == 0)
++trail;
d999 = rfs.back();
d999 = d999 < 100 ? (d999 < 10 ? 2 : 1) : 0;
zeroes -= d999;
int digits = rfs.size() * 3 - d999;
total += double(zeroes) / digits;
double ratio = total / f;
if (ratio >= 0.16)
first = 0;
else if (first == 0)
first = f;
if (f == 100 || f == 1000 || f == 10000) {
std::cout << "Mean proportion of zero digits in factorials to " << f
<< " is " << ratio << ". (" << elapsed(t0) << "ms)\n";
}
}
std::cout << "The mean proportion dips permanently below 0.16 at " << first
<< ". (" << elapsed(t0) << "ms)\n";
}
- Output:
Mean proportion of zero digits in factorials to 100 is 0.2467531862. (0ms) Mean proportion of zero digits in factorials to 1000 is 0.2035445511. (1ms) Mean proportion of zero digits in factorials to 10000 is 0.1730038482. (152ms) The mean proportion dips permanently below 0.16 at 47332. (4598ms)
Go
Brute force
Timings here are 2.8 seconds for the basic task and 182.5 seconds for the stretch goal.
package main
import (
"fmt"
big "github.com/ncw/gmp"
"rcu"
)
func main() {
fact := big.NewInt(1)
sum := 0.0
first := int64(0)
firstRatio := 0.0
fmt.Println("The mean proportion of zero digits in factorials up to the following are:")
for n := int64(1); n <= 50000; n++ {
fact.Mul(fact, big.NewInt(n))
bytes := []byte(fact.String())
digits := len(bytes)
zeros := 0
for _, b := range bytes {
if b == '0' {
zeros++
}
}
sum += float64(zeros)/float64(digits)
ratio := sum / float64(n)
if n == 100 || n == 1000 || n == 10000 {
fmt.Printf("%6s = %12.10f\n", rcu.Commatize(int(n)), ratio)
}
if first > 0 && ratio >= 0.16 {
first = 0
firstRatio = 0.0
} else if first == 0 && ratio < 0.16 {
first = n
firstRatio = ratio
}
}
fmt.Printf("%6s = %12.10f", rcu.Commatize(int(first)), firstRatio)
fmt.Println(" (stays below 0.16 after this)")
fmt.Printf("%6s = %12.10f\n", "50,000", sum / 50000)
}
- Output:
The mean proportion of zero digits in factorials up to the following are: 100 = 0.2467531862 1,000 = 0.2035445511 10,000 = 0.1730038482 47,332 = 0.1599999958 (stays below 0.16 after this) 50,000 = 0.1596200546
'String math' and base 1000
Much quicker than before with 10,000 now being reached in 0.35 seconds and the stretch goal in about 5.5 seconds.
package main
import (
"fmt"
"rcu"
)
var rfs = []int{1} // reverse factorial(1) in base 1000
var zc = make([]int, 999)
func init() {
for x := 1; x <= 9; x++ {
zc[x-1] = 2 // 00x
zc[10*x-1] = 2 // 0x0
zc[100*x-1] = 2 // x00
var y = 10
for y <= 90 {
zc[y+x-1] = 1 // 0yx
zc[10*y+x-1] = 1 // y0x
zc[10*(y+x)-1] = 1 // yx0
y += 10
}
}
}
func main() {
total := 0.0
trail := 1
first := 0
firstRatio := 0.0
fmt.Println("The mean proportion of zero digits in factorials up to the following are:")
for f := 2; f <= 10000; f++ {
carry := 0
d999 := 0
zeros := (trail - 1) * 3
j := trail
l := len(rfs)
for j <= l || carry != 0 {
if j <= l {
carry = rfs[j-1]*f + carry
}
d999 = carry % 1000
if j <= l {
rfs[j-1] = d999
} else {
rfs = append(rfs, d999)
}
if d999 == 0 {
zeros += 3
} else {
zeros += zc[d999-1]
}
carry /= 1000
j++
}
for rfs[trail-1] == 0 {
trail++
}
// d999 = quick correction for length and zeros
d999 = rfs[len(rfs)-1]
if d999 < 100 {
if d999 < 10 {
d999 = 2
} else {
d999 = 1
}
} else {
d999 = 0
}
zeros -= d999
digits := len(rfs)*3 - d999
total += float64(zeros) / float64(digits)
ratio := total / float64(f)
if ratio >= 0.16 {
first = 0
firstRatio = 0.0
} else if first == 0 {
first = f
firstRatio = ratio
}
if f == 100 || f == 1000 || f == 10000 {
fmt.Printf("%6s = %12.10f\n", rcu.Commatize(f), ratio)
}
}
fmt.Printf("%6s = %12.10f", rcu.Commatize(first), firstRatio)
fmt.Println(" (stays below 0.16 after this)")
fmt.Printf("%6s = %12.10f\n", "50,000", total/50000)
}
- Output:
Same as 'brute force' version.
Java
import java.math.BigInteger;
import java.util.List;
public final class DistributionInFactorials {
public static void main(String[] aArgs) {
List<Integer> limits = List.of( 100, 1_000, 10_000 );
for ( Integer limit : limits ) {
meanFactorialDigits(limit);
}
}
private static void meanFactorialDigits(Integer aLimit) {
BigInteger factorial = BigInteger.ONE;
double proportionSum = 0.0;
double proportionMean = 0.0;
for ( int n = 1; n <= aLimit; n++ ) {
factorial = factorial.multiply(BigInteger.valueOf(n));
String factorialString = factorial.toString();
int digitCount = factorialString.length();
long zeroCount = factorialString.chars().filter( ch -> ch == '0' ).count();
proportionSum += (double) zeroCount / digitCount;
proportionMean = proportionSum / n;
}
String result = String.format("%.8f", proportionMean);
System.out.println("Mean proportion of zero digits in factorials from 1 to " + aLimit + " is " + result);
}
}
- Output:
Mean proportion of zero digits in factorials from 1 to 100 is 0.24675319 Mean proportion of zero digits in factorials from 1 to 1000 is 0.20354455 Mean proportion of zero digits in factorials from 1 to 10000 is 0.17300385
jq
Works with jq
The precision of jq's integer arithmetic is not up to this task, so in the following we borrow from the "BigInt" library and use a string representation of integers.
Unfortunately, although gojq (the Go implementation of jq) does support unbounded-precision integer arithmetic, it is unsuited for the task because of memory management issues.
From BigInt.jq
# multiply two decimal strings, which may be signed (+ or -)
def long_multiply(num1; num2):
def stripsign:
.[0:1] as $a
| if $a == "-" then [ -1, .[1:]]
elif $a == "+" then [ 1, .[1:]]
else [1, .]
end;
def adjustsign(sign):
if sign == 1 then . else "-" + . end;
# mult/2 assumes neither argument has a sign
def mult(num1;num2):
(num1 | explode | map(.-48) | reverse) as $a1
| (num2 | explode | map(.-48) | reverse) as $a2
| reduce range(0; num1|length) as $i1
([]; # result
reduce range(0; num2|length) as $i2
(.;
($i1 + $i2) as $ix
| ( $a1[$i1] * $a2[$i2] + (if $ix >= length then 0 else .[$ix] end) ) as $r
| if $r > 9 # carrying
then
.[$ix + 1] = ($r / 10 | floor) + (if $ix + 1 >= length then 0 else .[$ix + 1] end )
| .[$ix] = $r - ( $r / 10 | floor ) * 10
else
.[$ix] = $r
end
)
)
| reverse | map(.+48) | implode;
(num1|stripsign) as $a1
| (num2|stripsign) as $a2
| if $a1[1] == "0" or $a2[1] == "0" then "0"
elif $a1[1] == "1" then $a2[1]|adjustsign( $a1[0] * $a2[0] )
elif $a2[1] == "1" then $a1[1]|adjustsign( $a1[0] * $a2[0] )
else mult($a1[1]; $a2[1]) | adjustsign( $a1[0] * $a2[0] )
end;
The task
def count(s): reduce s as $x (0; .+1);
def meanfactorialdigits:
def digits: tostring | explode;
def nzeros: count( .[] | select(. == 48) ); # "0" is 48
. as $N
| 0.16 as $goal
| label $out
| reduce range( 1; 1+$N ) as $i ( {factorial: "1", proportionsum: 0.0, first: null };
.factorial = long_multiply(.factorial; $i|tostring)
| (.factorial|digits) as $d
| .proportionsum += ($d | (nzeros / length))
| (.proportionsum / $i) as $propmean
| if .first
then if $propmean > $goal then .first = null else . end
elif $propmean <= $goal then .first = $i
else .
end)
| "Mean proportion of zero digits in factorials to \($N) is \(.proportionsum/$N);" +
(if .first then " mean <= \($goal) from N=\(.first) on." else " goal (\($goal)) unmet." end);
# The task:
100, 1000, 10000 | meanfactorialdigits
- Output:
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216; goal (0.16) unmet. Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458; goal (0.16) unmet. Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707; goal (0.16) unmet.
Julia
function meanfactorialdigits(N, goal = 0.0)
factoril, proportionsum = big"1", 0.0
for i in 1:N
factoril *= i
d = digits(factoril)
zero_proportion_in_fac = count(x -> x == 0, d) / length(d)
proportionsum += zero_proportion_in_fac
propmean = proportionsum / i
if i > 15 && propmean <= goal
println("The mean proportion dips permanently below $goal at $i.")
break
end
if i == N
println("Mean proportion of zero digits in factorials to $N is ", propmean)
end
end
end
@time foreach(meanfactorialdigits, [100, 1000, 10000])
@time meanfactorialdigits(50000, 0.16)
- Output:
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216 Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458 Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707 3.030182 seconds (297.84 k allocations: 1.669 GiB, 0.83% gc time, 0.28% compilation time) The mean proportion dips permanently below 0.16 at 47332. 179.157788 seconds (3.65 M allocations: 59.696 GiB, 1.11% gc time)
Base 1000 version
function init_zc()
zc = zeros(Int, 999)
for x in 1:9
zc[x] = 2 # 00x
zc[10*x] = 2 # 0x0
zc[100*x] = 2 # x00
for y in 10:10:90
zc[y+x] = 1 # 0yx
zc[10*y+x] = 1 # y0x
zc[10*(y+x)] = 1 # yx0
end
end
return zc
end
function meanfactorialzeros(N = 50000, verbose = true)
zc = init_zc()
rfs = [1]
total, trail, first, firstratio = 0.0, 1, 0, 0.0
for f in 2:N
carry, d999, zeroes = 0, 0, (trail - 1) * 3
j, l = trail, length(rfs)
while j <= l || carry != 0
if j <= l
carry = (rfs[j]) * f + carry
end
d999 = carry % 1000
if j <= l
rfs[j] = d999
else
push!(rfs, d999)
end
zeroes += (d999 == 0) ? 3 : zc[d999]
carry ÷= 1000
j += 1
end
while rfs[trail] == 0
trail += 1
end
# d999 = quick correction for length and zeroes:
d999 = rfs[end]
d999 = d999 < 100 ? d999 < 10 ? 2 : 1 : 0
zeroes -= d999
digits = length(rfs) * 3 - d999
total += zeroes / digits
ratio = total / f
if ratio >= 0.16
first = 0
firstratio = 0.0
elseif first == 0
first = f
firstratio = ratio
end
if f in [100, 1000, 10000]
verbose && println("Mean proportion of zero digits in factorials to $f is $ratio")
end
end
verbose && println("The mean proportion dips permanently below 0.16 at $first.")
end
meanfactorialzeros(100, false)
@time meanfactorialzeros()
- Output:
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216 Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458 Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707 The mean proportion dips permanently below 0.16 at 47332. 4.638323 seconds (50.08 k allocations: 7.352 MiB)
Mathematica/Wolfram Language
ClearAll[ZeroDigitsFractionFactorial]
ZeroDigitsFractionFactorial[n_Integer] := Module[{m},
m = IntegerDigits[n!];
Count[m, 0]/Length[m]
]
ZeroDigitsFractionFactorial /@ Range[6] // Mean // N
ZeroDigitsFractionFactorial /@ Range[25] // Mean // N
ZeroDigitsFractionFactorial /@ Range[100] // Mean // N
ZeroDigitsFractionFactorial /@ Range[1000] // Mean // N
ZeroDigitsFractionFactorial /@ Range[10000] // Mean // N
fracs = ParallelMap[ZeroDigitsFractionFactorial, Range[50000], Method -> ("ItemsPerEvaluation" -> 100)];
means = Accumulate[N@fracs]/Range[Length[fracs]];
len = LengthWhile[Reverse@means, # < 0.16 &];
50000 - len + 1
- Output:
0.111111 0.267873 0.246753 0.203545 0.173004 47332
Nim
Task
import strutils, std/monotimes
import bignum
let t0 = getMonoTime()
var sum = 0.0
var f = newInt(1)
var lim = 100
for n in 1..10_000:
f *= n
let str = $f
sum += str.count('0') / str.len
if n == lim:
echo n, ":\t", sum / float(n)
lim *= 10
echo()
echo getMonoTime() - t0
- Output:
100: 0.2467531861674322 1000: 0.2035445511031646 10000: 0.1730038482418671 (seconds: 2, nanosecond: 857794404)
Stretch task
At each step, we eliminate the trailing zeroes to reduce the length of the number and save some time. But this is not much, about 8%.
import strutils, std/monotimes
import bignum
let t0 = getMonoTime()
var sum = 0.0
var first = 0
var f = newInt(1)
var count0 = 0
for n in 1..<50_000:
f *= n
while f mod 10 == 0: # Reduce the length of "f".
f = f div 10
inc count0
let str = $f
sum += (str.count('0') + count0) / (str.len + count0)
if sum / float(n) < 0.16:
if first == 0: first = n
else:
first = 0
echo "Permanently below 0.16 at n = ", first
echo "Execution time: ", getMonoTime() - t0
- Output:
Permanently below 0.16 at n = 47332 Execution time: (seconds: 190, nanosecond: 215845101)
Pascal
Doing the calculation in Base 1,000,000,000 like in Primorial_numbers#alternative.
The most time consuming is converting to string and search for zeros.
Therefor I do not convert to string.I divide the base in sections of 3 digits with counting zeros in a lookup table.
program Factorial;
{$IFDEF FPC} {$MODE DELPHI} {$Optimization ON,ALL} {$ENDIF}
uses
sysutils;
type
tMul = array of LongWord;
tpMul = pLongWord;
const
LongWordDec = 1000*1000*1000;
LIMIT = 50000;
var
CountOfZero : array[0..999] of byte;
SumOfRatio :array[0..LIMIT] of extended;
procedure OutMul(pMul:tpMul;Lmt :NativeInt);
// for testing
Begin
write(pMul[lmt]);
For lmt := lmt-1 downto 0 do
write(Format('%.9d',[pMul[lmt]]));
writeln;
end;
procedure InitCoZ;
//Init Lookup table for 3 digits
var
x,y : integer;
begin
fillchar(CountOfZero,SizeOf(CountOfZero),#0);
CountOfZero[0] := 3; //000
For x := 1 to 9 do
Begin
CountOfZero[x] := 2; //00x
CountOfZero[10*x] := 2; //0x0
CountOfZero[100*x] := 2; //x00
y := 10;
repeat
CountOfZero[y+x] := 1; //0yx
CountOfZero[10*y+x] := 1; //y0x
CountOfZero[10*(y+x)] := 1; //yx0
inc(y,10)
until y > 100;
end;
end;
function getFactorialDecDigits(n:NativeInt):NativeInt;
var
res: extended;
Begin
result := -1;
IF (n > 0) AND (n <= 1000*1000) then
Begin
res := 0;
repeat res := res+ln(n); dec(n); until n < 2;
result := trunc(res/ln(10))+1;
end;
end;
function CntZero(pMul:tpMul;Lmt :NativeInt):NativeUint;
//count zeros in Base 1,000,000,000 number
var
q,r : LongWord;
i : NativeInt;
begin
result := 0;
For i := Lmt-1 downto 0 do
Begin
q := pMul[i];
r := q DIV 1000;
result +=CountOfZero[q-1000*r];//q-1000*r == q mod 1000
q := r;
r := q DIV 1000;
result +=CountOfZero[q-1000*r];
q := r;
r := q DIV 1000;
result +=CountOfZero[q-1000*r];
end;
//special case first digits no leading '0'
q := pMul[lmt];
while q >= 1000 do
begin
r := q DIV 1000;
result +=CountOfZero[q-1000*r];
q := r;
end;
while q > 0 do
begin
r := q DIV 10;
result += Ord( q-10*r= 0);
q := r;
end;
end;
function GetCoD(pMul:tpMul;Lmt :NativeInt):NativeUint;
//count of decimal digits
var
i : longWord;
begin
result := 9*Lmt;
i := pMul[Lmt];
while i > 1000 do
begin
i := i DIV 1000;
inc(result,3);
end;
while i > 0 do
begin
i := i DIV 10;
inc(result);
end;
end;
procedure DoChecks(pMul:tpMul;Lmt,i :NativeInt);
//(extended(1.0)* makes TIO.RUN faster // only using FPU?
Begin
SumOfRatio[i] := SumOfRatio[i-1] + (extended(1.0)*CntZero(pMul,Lmt))/GetCoD(pMul,Lmt);
end;
function MulByI(pMul:tpMul;UL,i :NativeInt):NativeInt;
var
prod : Uint64;
j : nativeInt;
carry : LongWord;
begin
result := UL;
carry := 0;
For j := 0 to result do
Begin
prod := i*pMul[0]+Carry;
Carry := prod Div LongWordDec;
pMul[0] := Prod - LongWordDec*Carry;
inc(pMul);
end;
IF Carry <> 0 then
Begin
inc(result);
pMul[0]:= Carry;
End;
end;
procedure getFactorialExact(n:NativeInt);
var
MulArr : tMul;
pMul : tpMul;
i,ul : NativeInt;
begin
i := getFactorialDecDigits(n) DIV 9 +10;
Setlength(MulArr,i);
pMul := @MulArr[0];
Ul := 0;
pMul[Ul]:= 1;
i := 1;
repeat
UL := MulByI(pMul,UL,i);
//Now do what you like to do with i!
DoChecks(pMul,UL,i);
inc(i);
until i> n;
end;
procedure Out_(i: integer);
begin
if i > LIMIT then
EXIT;
writeln(i:8,SumOfRatio[i]/i:18:15);
end;
var
i : integer;
Begin
InitCoZ;
SumOfRatio[0]:= 0;
getFactorialExact(LIMIT);
Out_(100);
Out_(1000);
Out_(10000);
Out_(50000);
i := limit;
while i >0 do
Begin
if SumOfRatio[i]/i >0.16 then
break;
dec(i);
end;
inc(i);
writeln('First ratio < 0.16 ', i:8,SumOfRatio[i]/i:20:17);
end.
- Output:
100 0.246753186167432 1000 0.203544551103165 10000 0.173003848241866 50000 0.159620054602269 First ratio < 0.16 47332 0.15999999579985665 Real time: 4.898 s CPU share: 99.55 % // 2.67s on 2200G freepascal 3.2.2
Perl
use strict;
use warnings;
use ntheory qw/factorial/;
for my $n (100, 1000, 10000) {
my($sum,$f) = 0;
$f = factorial $_ and $sum += ($f =~ tr/0//) / length $f for 1..$n;
printf "%5d: %.5f\n", $n, $sum/$n;
}
- Output:
100: 0.24675 1000: 0.20354 10000: 0.17300
Phix
Using "string math" to create reversed factorials, for slightly easier skipping of "trailing" zeroes, but converted to base 1000 and with the zero counting idea from Pascal, which sped it up threefold.
with javascript_semantics sequence rfs = {1} -- reverse factorial(1) in base 1000 function init_zc() sequence zc = repeat(0,999) for x=1 to 9 do zc[x] = 2 -- 00x zc[10*x] = 2 -- 0x0 zc[100*x] = 2 -- x00 for y=10 to 90 by 10 do zc[y+x] = 1 -- 0yx zc[10*y+x] = 1 -- y0x zc[10*(y+x)] = 1 -- yx0 end for end for return zc end function constant zc = init_zc() atom t0 = time(), total = 0 integer trail = 1, first = 0 for f=2 to iff(platform()=JS?10000:50000) do integer carry = 0, d999, zeroes = (trail-1)*3, j = trail, l = length(rfs) while j<=l or carry do if j<=l then carry = (rfs[j])*f+carry end if d999 = remainder(carry,1000) if j<=l then rfs[j] = d999 else rfs &= d999 end if zeroes += iff(d999=0?3:zc[d999]) carry = floor(carry/1000) j += 1 end while while rfs[trail]=0 do trail += 1 end while -- d999 := quick correction for length and zeroes: d999 = rfs[$] d999 = iff(d999<100?iff(d999<10?2:1):0) zeroes -= d999 integer digits = length(rfs)*3-d999 total += zeroes/digits atom ratio = total/f if ratio>=0.16 then first = 0 elsif first=0 then first = f end if if find(f,{100,1000,10000}) then string e = elapsed(time()-t0) printf(1,"Mean proportion of zero digits in factorials to %d is %.10f (%s)\n",{f,ratio,e}) end if end for if platform()!=JS then string e = elapsed(time()-t0) printf(1,"The mean proportion dips permanently below 0.16 at %d. (%s)\n",{first,e}) end if
- Output:
Mean proportion of zero digits in factorials to 100 is 0.2467531862 (0s) Mean proportion of zero digits in factorials to 1000 is 0.2035445511 (0.2s) Mean proportion of zero digits in factorials to 10000 is 0.1730038482 (2.3s) The mean proportion dips permanently below 0.16 at 47332. (1 minute and 2s)
(stretch goal removed under pwa/p2js since otherwise you'd get a blank screen for 2 or 3 minutes)
trailing zeroes only
Should you only be interested in the ratio of trailing zeroes, you can do that much faster:
with javascript_semantics atom t0 = time(), f10 = log10(1), total = 0 integer first = 0 for f=2 to 50000 do f10 += log10(f) integer digits = ceil(f10), zeroes = 0, v = 5 while v<=f do zeroes += floor(f/v) v *= 5 end while total += zeroes/digits atom ratio = total/f if ratio>=0.07 then first = 0 elsif first=0 then first = f end if if find(f,{100,1000,10000}) then printf(1,"Mean proportion of trailing zeroes in factorials to %d is %f\n",{f,ratio}) end if end for string e = elapsed(time()-t0) printf(1,"The mean proportion dips permanently below 0.07 at %d. (%s)\n",{first,e})
- Output:
Mean proportion of trailing zeroes in factorials to 100 is 0.170338 Mean proportion of trailing zeroes in factorials to 1000 is 0.116334 Mean proportion of trailing zeroes in factorials to 10000 is 0.081267 The mean proportion dips permanently below 0.07 at 31549. (0.1s)
Python
def facpropzeros(N, verbose = True):
proportions = [0.0] * N
fac, psum = 1, 0.0
for i in range(N):
fac *= i + 1
d = list(str(fac))
psum += sum(map(lambda x: x == '0', d)) / len(d)
proportions[i] = psum / (i + 1)
if verbose:
print("The mean proportion of 0 in factorials from 1 to {} is {}.".format(N, psum / N))
return proportions
for n in [100, 1000, 10000]:
facpropzeros(n)
props = facpropzeros(47500, False)
n = (next(i for i in reversed(range(len(props))) if props[i] > 0.16))
print("The mean proportion dips permanently below 0.16 at {}.".format(n + 2))
- Output:
The mean proportion of 0 in factorials from 1 to 100 is 0.24675318616743216. The mean proportion of 0 in factorials from 1 to 1000 is 0.20354455110316458. The mean proportion of 0 in factorials from 1 to 10000 is 0.17300384824186707. The mean proportion dips permanently below 0.16 at 47332.
The means can be plotted, showing a jump from 0 to over 0.25, followed by a slowly dropping curve:
import matplotlib.pyplot as plt
plt.plot([i+1 for i in range(len(props))], props)
Base 1000 version
def zinit():
zc = [0] * 999
for x in range(1, 10):
zc[x - 1] = 2 # 00x
zc[10 * x - 1] = 2 # 0x0
zc[100 * x - 1] = 2 # x00
for y in range(10, 100, 10):
zc[y + x - 1] = 1 # 0yx
zc[10 * y + x - 1] = 1 # y0x
zc[10 * (y + x) - 1] = 1 # yx0
return zc
def meanfactorialdigits():
zc = zinit()
rfs = [1]
total, trail, first = 0.0, 1, 0
for f in range(2, 50000):
carry, d999, zeroes = 0, 0, (trail - 1) * 3
j, l = trail, len(rfs)
while j <= l or carry != 0:
if j <= l:
carry = rfs[j-1] * f + carry
d999 = carry % 1000
if j <= l:
rfs[j-1] = d999
else:
rfs.append(d999)
zeroes += 3 if d999 == 0 else zc[d999-1]
carry //= 1000
j += 1
while rfs[trail-1] == 0:
trail += 1
# d999 is a quick correction for length and zeros
d999 = rfs[-1]
d999 = 0 if d999 >= 100 else 2 if d999 < 10 else 1
zeroes -= d999
digits = len(rfs) * 3 - d999
total += zeroes / digits
ratio = total / f
if f in [100, 1000, 10000]:
print("The mean proportion of zero digits in factorials to {} is {}".format(f, ratio))
if ratio >= 0.16:
first = 0
elif first == 0:
first = f
print("The mean proportion dips permanently below 0.16 at {}.".format(first))
import time
TIME0 = time.perf_counter()
meanfactorialdigits()
print("\nTotal time:", time.perf_counter() - TIME0, "seconds.")
- Output:
The mean proportion of zero digits in factorials to 100 is 0.24675318616743216 The mean proportion of zero digits in factorials to 1000 is 0.20354455110316458 The mean proportion of zero digits in factorials to 10000 is 0.17300384824186707 The mean proportion dips permanently below 0.16 at 47332. Total time: 648.3583232999999 seconds.
Raku
Works, but depressingly slow for 10000.
sub postfix:<!> (Int $n) { ( constant factorial = 1, 1, |[\*] 2..* )[$n] }
sink 10000!; # prime the iterator to allow multithreading
sub zs ($n) { ( constant zero-share = (^Inf).race(:32batch).map: { (.!.comb.Bag){'0'} / .!.chars } )[$n+1] }
.say for (
100
,1000
,10000
).map: -> \n { "{n}: {([+] (^n).map: *.&zs) / n}" }
- Output:
100: 0.24675318616743216 1000: 0.20354455110316458 10000: 0.17300384824186605
REXX
/*REXX program computes the mean of the proportion of "0" digits a series of factorials.*/
parse arg $ /*obtain optional arguments from the CL*/
if $='' | $="," then $= 100 1000 10000 /*not specified? Then use the default.*/
#= words($) /*the number of ranges to be used here.*/
numeric digits 100 /*increase dec. digs, but only to 100. */
big= word($, #); != 1 /*obtain the largest number in ranges. */
do i=1 for big /*calculate biggest ! using 100 digs.*/
!= ! * i /*calculate the factorial of BIG. */
end /*i*/
if pos('E', !)>0 then do /*In exponential format? Then get EXP.*/
parse var ! 'E' x /*parse the exponent from the number. */
numeric digits x+1 /*set the decimal digits to X plus 1.*/
end /* [↑] the +1 is for the dec. point.*/
title= ' mean proportion of zeros in the (decimal) factorial products for N'
say ' N │'center(title, 80) /*display the title for the output. */
say '───────────┼'center("" , 80, '─') /* " a sep " " " */
do j=1 for #; n= word($, j) /*calculate some factorial ranges. */
say center( commas(n), 11)'│' left(0dist(n), 75)... /*show results for above range.*/
end /*j*/
say '───────────┴'center("" , 80, '─') /*display a foot sep for the output. */
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas: parse arg ?; do jc=length(?)-3 to 1 by -3; ?=insert(',', ?, jc); end; return ?
/*──────────────────────────────────────────────────────────────────────────────────────*/
0dist: procedure; parse arg z; != 1; y= 0
do k=1 for z; != ! * k; y= y + countstr(0, !) / length(!)
end /*k*/
return y/z
- output when using the default inputs:
N │ mean proportion of zeros in the (decimal) factorial products for N ───────────┼──────────────────────────────────────────────────────────────────────────────── 100 │ 0.2467531861674322177784158871973526991129407033266153063813195937196095976... 1,000 │ 0.2035445511031646356400438031711455302985741167890402203486699704599684047... 10,000 │ 0.1730038482418660531800366428930706156810278809057883361518852958446868172... ───────────┴────────────────────────────────────────────────────────────────────────────────
Rust
fn init_zc() -> Vec<usize> {
let mut zc = vec![0; 1000];
zc[0] = 3;
for x in 1..=9 {
zc[x] = 2;
zc[10 * x] = 2;
zc[100 * x] = 2;
let mut y = 10;
while y <= 90 {
zc[y + x] = 1;
zc[10 * y + x] = 1;
zc[10 * (y + x)] = 1;
y += 10;
}
}
zc
}
fn main() {
use std::time::Instant;
let zc = init_zc();
let t0 = Instant::now();
let mut trail = 1;
let mut first = 0;
let mut total: f64 = 0.0;
let mut rfs = vec![1];
for f in 2..=50000 {
let mut carry = 0;
let mut d999: usize;
let mut zeroes = (trail - 1) * 3;
let len = rfs.len();
let mut j = trail - 1;
while j < len || carry != 0 {
if j < len {
carry += rfs[j] * f;
}
d999 = carry % 1000;
if j < len {
rfs[j] = d999;
} else {
rfs.push(d999);
}
zeroes += zc[d999];
carry /= 1000;
j += 1;
}
while rfs[trail - 1] == 0 {
trail += 1;
}
d999 = rfs[rfs.len() - 1];
d999 = if d999 < 100 {
if d999 < 10 {
2
} else {
1
}
} else {
0
};
zeroes -= d999;
let digits = rfs.len() * 3 - d999;
total += (zeroes as f64) / (digits as f64);
let ratio = total / (f as f64);
if ratio >= 0.16 {
first = 0;
} else if first == 0 {
first = f;
}
if f == 100 || f == 1000 || f == 10000 {
let duration = t0.elapsed();
println!(
"Mean proportion of zero digits in factorials to {} is {:.10}. ({}ms)",
f,
ratio,
duration.as_millis()
);
}
}
let duration = t0.elapsed();
println!(
"The mean proportion dips permanently below 0.16 at {}. ({}ms)",
first,
duration.as_millis()
);
}
- Output:
Mean proportion of zero digits in factorials to 100 is 0.2467531862. (0ms) Mean proportion of zero digits in factorials to 1000 is 0.2035445511. (1ms) Mean proportion of zero digits in factorials to 10000 is 0.1730038482. (149ms) The mean proportion dips permanently below 0.16 at 47332. (4485ms)
Ruby
[100, 1000, 10_000].each do |n|
v = 1
total_proportion = (1..n).sum do |k|
v *= k
digits = v.digits
Rational(digits.count(0), digits.size)
end
puts "The mean proportion of 0 in factorials from 1 to #{n} is #{(total_proportion/n).to_f}."
end
- Output:
The mean proportion of 0 in factorials from 1 to 100 is 0.24675318616743222. The mean proportion of 0 in factorials from 1 to 1000 is 0.20354455110316463. The mean proportion of 0 in factorials from 1 to 10000 is 0.17300384824186604.
Sidef
func mean_factorial_digits(n, d = 0) {
var v = 1
var total = 0.float
for k in (1..n) {
v *= k
total += v.digits.count(d)/v.len
}
total / n
}
say mean_factorial_digits(100)
say mean_factorial_digits(1000)
say mean_factorial_digits(10000)
- Output:
0.246753186167432217778415887197352699112940703327 0.203544551103164635640043803171145530298574116789 0.173003848241866053180036642893070615681027880906
Wren
Brute force
Very slow indeed, 10.75 minutes to reach N = 10,000.
import "./big" for BigInt
import "./fmt" for Fmt
var fact = BigInt.one
var sum = 0
System.print("The mean proportion of zero digits in factorials up to the following are:")
for (n in 1..10000) {
fact = fact * n
var bytes = fact.toString.bytes
var digits = bytes.count
var zeros = bytes.count { |b| b == 48 }
sum = sum + zeros / digits
if (n == 100 || n == 1000 || n == 10000) {
Fmt.print("$,6d = $12.10f", n, sum / n)
}
}
- Output:
The mean proportion of zero digits in factorials up to the following are: 100 = 0.2467531862 1,000 = 0.2035445511 10,000 = 0.1730038482
'String math' and base 1000
Around 60 times faster than before with 10,000 now being reached in about 10.5 seconds. Even the stretch goal is now viable and comes in at 5 minutes 41 seconds.
import "./fmt" for Fmt
var rfs = [1] // reverse factorial(1) in base 1000
var init = Fn.new { |zc|
for (x in 1..9) {
zc[x-1] = 2 // 00x
zc[10*x - 1] = 2 // 0x0
zc[100*x - 1] = 2 // x00
var y = 10
while (y <= 90) {
zc[y + x - 1] = 1 // 0yx
zc[10*y + x - 1] = 1 // y0x
zc[10*(y + x) - 1] = 1 // yx0
y = y + 10
}
}
}
var zc = List.filled(999, 0)
init.call(zc)
var total = 0
var trail = 1
var first = 0
var firstRatio = 0
System.print("The mean proportion of zero digits in factorials up to the following are:")
for (f in 2..50000) {
var carry = 0
var d999 = 0
var zeros = (trail-1) * 3
var j = trail
var l = rfs.count
while (j <= l || carry != 0) {
if (j <= l) carry = rfs[j-1]*f + carry
d999 = carry % 1000
if (j <= l) {
rfs[j-1] = d999
} else {
rfs.add(d999)
}
zeros = zeros + ((d999 == 0) ? 3 : zc[d999-1])
carry = (carry/1000).floor
j = j + 1
}
while (rfs[trail-1] == 0) trail = trail + 1
// d999 = quick correction for length and zeros
d999 = rfs[-1]
d999 = (d999 < 100) ? ((d999 < 10) ? 2 : 1) : 0
zeros = zeros - d999
var digits = rfs.count * 3 - d999
total = total + zeros/digits
var ratio = total / f
if (ratio >= 0.16) {
first = 0
firstRatio = 0
} else if (first == 0) {
first = f
firstRatio = ratio
}
if (f == 100 || f == 1000 || f == 10000) {
Fmt.print("$,6d = $12.10f", f, ratio)
}
}
Fmt.write("$,6d = $12.10f", first, firstRatio)
System.print(" (stays below 0.16 after this)")
Fmt.print("$,6d = $12.10f", 50000, total/50000)
- Output:
The mean proportion of zero digits in factorials up to the following are: 100 = 0.2467531862 1,000 = 0.2035445511 10,000 = 0.1730038482 47,332 = 0.1599999958 (stays below 0.16 after this) 50,000 = 0.1596200546