[PYTHON] Geschwindigkeitsvergleich jeder Sprache nach der Monte-Carlo-Methode

Einführung

[Monte-Carlo-Methode](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%AB%E3%83%AB%E3% 83% AD% E6% B3% 95) Der Geschwindigkeitsvergleich jeder Sprache wird durchgeführt, indem das Umfangsverhältnis in jeder Sprache unter Verwendung der Monte-Carlo-Methode berechnet wird. Die Monte-Carlo-Methode besteht darin, einen beliebigen Punkt (Zufallszahl) bei 1,0> = x> = 0, 1,0> = y> = 0 abzulegen, und der abgelegte Punkt fällt innerhalb des Kreises vom Ursprung (0,0). Das Verhältnis zwischen dem Ding und dem Ding, das außerhalb des Kreises gefallen ist, wird berechnet, und dieses Verhältnis wird zum Umfangsverhältnis. Obwohl es nahe an dem durch Berechnung erhaltenen Umfangsverhältnis liegt, gibt es natürlich keinen genauen Wert, aber ich denke, es ist sinnvoll, es in einer Programmiersprache zu implementieren. Der Grund ist -Die Geschwindigkeit der Gleitkommaberechnung kann verglichen werden. ・ Die Schleifengeschwindigkeit kann verglichen werden.

  1. Juni 2020 Ruby wurde hinzugefügt.
  2. Juni 2020 Die Berechnungsmethode von Python wurde geändert.
  3. Juni 2020 Die Angabe der Anzahl der Rostschleifen war falsch und wurde korrigiert.
  4. Juni 2020 Zusätzliche Messung der von @ tatsuya6502 bereitgestellten Xoroshiro-Versionsquelle für Rost

Unten jede Sprachquelle perl

Da Perl ein sehr schnelles Image hatte, das ich bisher ausprobiert hatte, habe ich es als Benchmark (≒ Standard) vorbereitet. Da die Quelle einfach ist, sollte sie aufgrund der Objektorientierung mit hoher Geschwindigkeit ohne Overhead arbeiten.

montecarlo.pl


use Time::HiRes qw( gettimeofday tv_interval);

local $ave = 0;

local $time_start, $time_end, $time_split = 0;

local $max_times    = 10000000;
local $test_times   = 100;

local $cnt = 0;

for ( $i = 1 ; $i <= $test_times ; $i++ ) {

    print($i."\n");

    $time_start = [gettimeofday];
    $cnt = 0;
    for ( $j = 0 ; $j < $max_times ; $j++) {
        $x = rand();
        $y = rand();

        if ( $x * $x + $y * $y <= 1) {
            $cnt++;
        }
    }

    $time_split = tv_interval($time_start);
    print("pi ".(4 * $cnt / $max_times)."\n");
    print("split:".$time_split."\n");

    $ave += $time_split;
}

print("AVE:".($ave / $test_times)."\n");
~                                                                                                                    ~                                                                                                                    

C Sprache

Vorerst habe ich es vorbereitet, weil "C schnell ist, nicht wahr?" Es kann schneller sein, wenn Sie es fest einstellen, Ich habe versucht, es auf dieser Ebene zu unterdrücken, weil die Codierung einfach ist.

montecarlo.c


#include <stdio.h>
#include <stdlib.h>
#include <time.h>

float montecarlo();

void main() {

    float ave = 0;
    int times = 100;

    for (int i = 1 ; i <= times ; i++){
        printf("%03d\n", i );
        ave += montecarlo();
    }

    printf("AVE %f\n\n", ave / times);

}

float montecarlo() {

    clock_t time_start, time_end;
    double  time_split;
    int times = 10000000;
    float x, y;

    time_start = clock();

    int cnt = 0;
    for ( int i = 0; i < times ; i++) {
        x = (float)rand() / (float)RAND_MAX;
        y = (float)rand() / (float)RAND_MAX;

        if ( (x * x + y * y) <= 1) {
            cnt++;
        }
    }

    time_end = clock();

    time_split = (double)(time_end - time_start) / 1000000;
    printf("%f\n", 4.0 * cnt / times);
    printf("time_split : %lf\n", time_split);

    return(time_split);

}

geh Sprache

Da go vorher einen guten Ruf hatte, habe ich es als Benchmark vorbereitet, der sich von Perl unterscheidet. Wie dünn kann es in C-Sprache sein, da es sich um eine Kompilierungssprache handelt? Das interessiert mich auch.

montecarlo.go


package main

import (
        "fmt"
        "time"
        "math/rand"
)

var i, j, cnt int
var x, y float64
var time_start, time_end int64
var ave, time_split float64

const MAX_TIMES = 10000000
const TEST_TIMES = 100

func main() {
        //fmt.Printf("%03d\n", 10)

        //fmt.Printf("%d\n", time.Now())
        //fmt.Printf("%f\n", float64(time.Now().UnixNano()) / 1000000000.0)
        //fmt.Printf("%f\n", float64(time.Now().UnixNano()) / 1000000000.0)
        //fmt.Printf("%f\n", float64(time.Now().UnixNano()) / 1000000000.0)

        rand.Seed(time.Now().UnixNano())

        ave := 0.0
        for i := 1 ; i <= TEST_TIMES ; i++ {

                fmt.Printf("%03d times\n", i)

                time_start      := time.Now().UnixNano()
                cnt := 0
                for j := 0 ; j <  MAX_TIMES ; j++ {

                        x := rand.Float64()
                        y := rand.Float64()

                        if x * x + y * y <= 1 {
                                cnt++
                        }

                }
                fmt.Printf("pi : %f\n", 4 * float64(cnt) / float64(MAX_TIMES))

                time_end        := time.Now().UnixNano()
                time_split      := float64(time_end - time_start) / 1000000000
                fmt.Printf("time : %f\n", time_split)
                ave += time_split
                //ave := time_split

        }

        fmt.Printf("AVE : %f\n", ave / TEST_TIMES)

}

Java

Als Zusammenstellungssprache denke ich, dass es derzeit als Eisenplatte positioniert ist. (Obwohl es Meinungen für jeden geben kann ...) Es wird erwartet, dass es aufgrund der dazwischenliegenden VM langsamer als die C-Sprache ist, aber in der Vergangenheit scheint es nicht tödlich langsam zu sein.

montecarlo.java


import java.util.Random;
import java.util.*;


class Montecarlo {
    public static void main(String[] args) {

        //System.out.println( getNowTime() );

                //Geben Sie den Radius des Kreises an
                double iR = 1.0;

                //Geben Sie die Anzahl der Ziehungen an
                int MAX_POINT = 10000000;

        //Geben Sie die Anzahl der Tests an
        int TEST_TIMES = 100;

                //Zufällige Objektdefinition
                Random rand = new Random();

        //Start- und Endzeiten
        long time_start, time_end = 0;

        double time_split;
        double ave = 0.0;

                //Definition der Sicherungsvariablen für den Zufallswert
                double ranValue = 0.0;
                double POS_X = 0.0;
                double POS_Y = 0.0;

        for ( int j = 1 ; j <= TEST_TIMES ; j ++) {

            //System.out.println("%03d", j);
            System.out.printf("%03d\n", j);

            //Startzeit
            time_start = System.nanoTime();
                //System.out.println( "start : " + time_start );

            //Zählen Sie die Anzahl der Fälle, die in einen Bogen gefallen sind
            int HIT_COUNT = 0;

            //Initialisierung von Arbeitsvariablen für die Ausgabe
            for ( int i = 0 ; i < MAX_POINT ; i++ ) {

                POS_X = rand.nextDouble();
                POS_Y = rand.nextDouble();

                if ( iR >= POS_X * POS_X + POS_Y * POS_Y )  {
                    HIT_COUNT++;
                }

            }
            // System.out.println(HIT_COUNT );
            System.out.println( (  4 * HIT_COUNT  / (double)MAX_POINT ) );

            //Endzeit
            time_end = System.nanoTime();

                //System.out.println( "end   : " + time_end );

            time_split = (double)(time_end - time_start) / 1000000000.0;

                //System.out.println( "split : " + (time_end - time_start) );
                System.out.println( "split : " + time_split );

            ave += time_split;

        }

        //System.out.println( getNowTime() );
        System.out.println( "AVE : " + ave / TEST_TIMES );

    }

        ///Aktuelle Zeit JJJJ/mm/dd hh:mm:ss(jpn)Holen Sie sich in Format
        public static String getNowTime() {

                return(String.format("%1$tF %1$tT" ,Calendar.getInstance()));

        }

}

lua Es hat den Ruf, leicht als Skriptsprache zu sein, also habe ich es hinzugefügt. Als Sprachspezifikation ist es ein Image, das schnell ist, weil es Anweisungen verwendet, die dem Betriebssystem nahe kommen.

montecarlo.lua


local socket = require("socket")

math.randomseed(os.time())

MAX_LOOP = 10000000
TEST_TIMES = 100

ave = 0.0
for i = 1, TEST_TIMES do
    print(string.format("%03d times", i))
    time_start  = socket.gettime()

    cnt = 0
    for j = 1 , MAX_LOOP do
        x = math.random()
        y = math.random()

        if x * x + y * y <= 1 then
            cnt = cnt + 1
        end

    end

    time_end    = socket.gettime()

    time_split  = time_end - time_start

    print(string.format("pi    : %f", 4 * cnt / MAX_LOOP))
    print(string.format("split : %f", time_split))

    ave = ave + time_split

end

print(string.format("ave : %f", ave / TEST_TIMES))

python Unnötig zu sagen, es ist Python. Dieses Mal werden wir mit der 2. und 3. Serie sowie mit Pypy vergleichen.

montecarlo.py


import random
import time
import math

_times = 10000000

def pi():
    _time_start = time.time()

    _cnt = 0
    for i in range(_times):

        _x = random.random()
        _y = random.random()

        #if  _x ** 2 + _y **2 <= 1:
        if  _x * _x + _y * _y <= 1:

            _cnt += 1

    print( 4.0 * _cnt / _times )

    _time_end = time.time()

    _time_split = _time_end - _time_start
    print(_time_split)

    return _time_split

_test = 100

_ave = 0.0
for _i in range(_test):
    print('{:03d} times'.format(_i+1))
    _ave += pi()

print('ave: {} s'.format(_ave/_test))

Rust Rust ist eine Sprache, die in der KI und beim maschinellen Lernen Aufmerksamkeit erregt. Es ist eine Sprache, die schneller als Python und einfacher zu entwickeln ist als C.

Cargo.toml


[package]
name = "montecarlo"
version = "0.1.0"
authors = ["ubuntu"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.6"
floating-duration="0.1.2"

src/main.rs


fn main() {

    use rand::Rng;                  //Für Zufallszahlen
    use std::time::Instant;         //Zur Zeiterfassung
    use floating_duration::TimeAsFloat; //Zur Umstellung von Zeit auf Float

    println!("Hello, world!");

    let loop_max = 10000000;        //Anzahl der Treffer
    let test_max = 100;             //Schleife, um den Durchschnitt zu erhalten

    let mut x: f32;
    let mut y: f32;

    let mut rng = rand::thread_rng();//Randseed-Einstellungen

    let mut split_time: f32 = 0.0;
    //for _test_count in 1..test_max {
    for _test_count in 1..=test_max {
        println!("times:{:?}", _test_count );
        let start_time = Instant::now();

        let mut count = 0;
        //for _loot_count in 1..loop_max {
        for _loot_count in 1..=loop_max {
            x = rng.gen_range(0., 1.);  //Zufallszahl 0.0~1.0
            y = rng.gen_range(0., 1.);

            if x * x + y * y <= 1.0 {
                count = count + 1;
            }

        }
        println!("pi:{}", 4.0 * count as f32 / loop_max as f32); //als f32 ist ein Typ gegossen
        let end_time = start_time.elapsed().as_fractional_secs();//Zeit in Sekunden umrechnen
        println!("time:{:?}", end_time );

        split_time = split_time + end_time as f32;

    }

    println!("AVE:{}", split_time / test_max as f32);

}

Xoroshiro-Versionsquelle bereitgestellt von @ tatsuya6502

Cargo.toml


[package]
name = "montecarlo"
version = "0.1.0"
authors = ["ubuntu"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.7"
rand_xoshiro = "0.4"

src/main.rs


//Für Zufallszahlen
use rand::Rng;
use rand_xoshiro::{rand_core::SeedableRng, Xoroshiro128Plus};

//Zur Zeiterfassung
use std::time::{Instant, SystemTime};

const LOOP_MAX: usize = 10_000_000; //Anzahl der Treffer
const TEST_MAX: usize = 100; //Schleife, um den Durchschnitt zu erhalten

fn main() -> Result<(), Box<dyn std::error::Error>> {
    //Setze zufälligen Samen
    let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
    let mut rng = Xoroshiro128Plus::seed_from_u64(now.as_millis() as u64);

    let mut split_time: f32 = 0.0;
    for _test_count in 1..=TEST_MAX {
        println!("times:{}", _test_count);
        let start_time = Instant::now();

        let mut count = 0;
        for _loot_count in 0..LOOP_MAX {
            //Zufallszahlen generieren[0.0, 1.0)・ ・ 0.0 oder mehr 1.Weniger als 0
            let x: f32 = rng.gen_range(0.0, 1.0);
            let y: f32 = rng.gen_range(0.0, 1.0);

            if x * x + y * y <= 1.0 {
                count += 1;
            }
        }
        println!("pi:{}", 4.0 * count as f32 / LOOP_MAX as f32); //als f32 ist ein Typ gegossen
        let end_time = start_time.elapsed().as_secs_f32(); //Zeit in Sekunden umrechnen
        println!("time:{}", end_time);

        split_time += end_time as f32;
    }

    println!("AVE:{}", split_time / TEST_MAX as f32);
    Ok(())
}

Nim Zum Vergleich ...

montecarlo.nim


import random
import times

randomize()

const TEST_MAX = 10000000
const LOOP_MAX = 100

var x, y = 0.0

var ave = 0.0

for loop in 1..LOOP_MAX:
    echo $loop & " times"

    var time_start = cpuTime()
    var count = 0
    for test in 1..TEST_MAX:

        x = rand(0.0..1.0)
        y = rand(0.0..1.0)

        # echo $x
        # echo $y

        if ( x * x + y * y <= 1):
            count += 1

    echo "pi:" &  repr(float(4.0 * float(count) / float(TEST_MAX)))

    var time_split = cpuTime() - time_start

    echo "split" & repr(time_split)
    ave += time_split

echo "AVE:" & repr(ave / float(LOOP_MAX))
                                                                                                                    ~                                                                                                                    

Ruby Ich habe Ruby hinzugefügt, weil @scivola die Quelle bereitgestellt hat.

montecarlo.rb


TIMES = 10000000

def pi
  time_start = Time.now

  cnt = 0
  TIMES.times do
    x = rand
    y = rand

    if  x * x + y * y <= 1
      cnt += 1
    end
  end

  puts 4.0 * cnt / TIMES

  time_end = Time.now

  time_split = time_end - time_start
  puts time_split

   time_split
end

test = 100

ave = 0.0

test.times do |i|
    puts "%03d times" % (i + 1)
    ave += pi
end

puts "ave: #{ ave / test } s"

Ergebnis

perl 5.30
	AVE:8.93247789s

java 14.0.1
	AVE: 1.4161036380199996s

c
	gcc 9.3.0

	gcc montecarlo.c -o pi

keine gcc-optimierung
	AVE:1.501472s

Optimierung der Ausführungsgeschwindigkeit von gcc-O3
	AVE:1.425400s

python 2.7.18
	AVE:14.216013s

pypy 7.3.1 with GCC 9.3.0
	ave: 0.983056025505

python 3.8.2
	AVE:12.485190s
pypy3 7.3.1 with GCC 9.3.0
	ave: 1.1475282835960388 s

go 1.13.8
	AVE:2.132493

lua 5.3
	AVE:6.715329

rust (cargo 1.44.0)
	cargo run --release
	AVE 0.507196783
	
	cargo run
	AVE 16.449156

Nim 1.0.6
    nim c -r montecarlo.nim
    AVE 7.2063023393
    
    nim c -r -d:release montecarlo.nim
    AVE:0.3236947073200001

Hinzugefügt am 28. Juni 2020

Rubin hinzugefügt.
 Ruby 2.7.0dev (2019-12-25 master e1e1d92277) [aarch64-linux]
    ave: 7.5495061204099985 s

Die Python-Quelle wurde behoben.
 if  _x ** 2 + _y **2 <= 1:    ①
 ↓
 if  _x * _x  + _y * _y <= 1:  ②

 ※python 3.8.Messung von 2
① Wiedererfassung
    ave: 11.132939925193787 s
 ②
    ave: 9.153075976371765 s
* Messung von Pypy3
① Wiedererfassung
    ave: 1.0760090994834899 s
 ②
    ave: 1.3655683732032775 s
Das?

Eine Rostschleife wurde behoben.
    for _test_count in 1..test_max {
        for _loot_count in 1..loop_max { ①
     ↓
    for _test_count in 1..=test_max {
        for _loot_count in 1..=loop_max { ②

 cargo run --Messung freigeben
① Wiedererfassung
    AVE:0.5022585
 ②
    AVE:0.51400733

Mit Rost@Wir haben die Quelle der Xoroshiro-Version gemessen, die von tatsuya6502 bereitgestellt wird.

 AVE:0.21163946

Fazit

Auf dieser Ebene wurde ~~ Nim ~~ Rost als der schnellste bewertet. In Bezug auf die Geschwindigkeit

~~ Nim> rost> pypy> C = java> pypy3> go> lua> rubin> perl> python2 serie> python3 serie ~~ Rost (Xoroshiro-Version)> Nim> Rost> Pypy> C = Java> = Pypy3> go> lua> rubin> perl> python2-Serie> python3-Serie

ist geworden. Es ist richtig kompilierte Sprache> Skriptsprache. Natürlich kann meine Codierung schlecht sein und "auf diese Weise wird es schneller". Es ist jedoch unwahrscheinlich, dass sich die Rangfolge signifikant ändert, selbst wenn ein gewisser Einfallsreichtum verwendet wird, um die Rangfolge um einen Schritt zu ändern.

Besonders hervorzuheben ist Python, und durch die Verwendung von pypy wurde bestätigt (möglich), dass es mit einer Geschwindigkeit nahe der C-Sprache funktioniert (natürlich funktioniert die Quelle, wie sie ist, möglicherweise nicht mit pypy, und die Bibliothek wird pypy. Es wird möglicherweise nicht unterstützt. Ich denke jedoch, dass es einen Versuch wert ist, wenn Sie es mit der flexiblen Beschreibung von Python beschleunigen können.

Hinzugefügt am 28. Juni 2020 Der Rubin ist schneller als ich erwartet hatte und ich kann meine Überraschung nicht verbergen. Als ich es vorher versuchte, war es ungefähr c: ruby = 1: 20, also habe ich es auch dieses Mal erwartet, aber ich wurde brillant verraten. Wenn ich @scivola keinen Vorschlag machen würde, würde ich ihn ignorieren. Vielen Dank.

Das mysteriöse Ergebnis dieses Quellfixes ist, dass Python beim Starten mit Python3 schneller ist, beim Starten mit Pypy3 jedoch langsamer. (Bitte um Kommentare von Experten) Übrigens habe ich in der Quelle dieses Artikels kommentiert, um den Unterschied zu zeigen, aber da ich ihn in der tatsächlichen Messquelle ersetzt habe, hat sich die Bewertung des Kommentars nicht verlangsamt. (Ich denke, es gab so etwas im alten Basic ...)

Der Unterschied zwischen Rost und dem Pseudozufallszahlengenerator ist offensichtlich. Laut der von @ tatsuya6502 bereitgestellten Xoroshiro-Versionsquelle wurde festgestellt, dass sich der Pseudozufallszahlengenerator ebenfalls an der richtigen Stelle befindet. Vielen Dank für den Hinweis.

Dieser Artikel wird gelegentlich aktualisiert. Wenn es eine Sprache gibt, die gut aussieht, werde ich sie hinzufügen.

Recommended Posts

Geschwindigkeitsvergleich jeder Sprache nach der Monte-Carlo-Methode
Vergleich der Stapelverarbeitungsgeschwindigkeit nach Sprache
Schätzung von π nach der Monte-Carlo-Methode
Monte-Carlo-Methode
Finden Sie das Verhältnis der Fläche des Biwa-Sees nach der Monte-Carlo-Methode
Dominion-Kompressionsspiel nach Monte-Carlo-Methode analysiert
Die erste Markov-Ketten-Monte-Carlo-Methode von PyStan
Berechnung der kürzesten Route nach der Monte-Carlo-Methode
Einführung in die Monte-Carlo-Methode
[Wissenschaftlich-technische Berechnung nach Python] Monte-Carlo-Simulation nach der Metropolenmethode der Thermodynamik des 2D-Anstiegsspinsystems
Simulieren Sie die Monte-Carlo-Methode in Python
Vergleich der Berechnungsgeschwindigkeit durch Implementierung von Python mpmath (willkürliche Genauigkeitsberechnung) (Hinweis)
Geschwindigkeitsvergleich der Python-XML-Perspektive
Geschwindigkeitsverbesserung durch Selbstimplementierung von numpy.random.multivariate_normal
Ich konnte pypy3.6-7.3.1 nicht mit macOS + pyenv installieren, aber ich konnte pypy3.6-7.3.0 installieren. Ich fühlte den Wind von Pypy nach der Monte-Carlo-Methode.
Geschwindigkeitsvergleich beim Umschalten nach Gruppen nach Pandas
Zusammenfassung der Hosting-Seiten der Bibliothek nach Sprache
Versuchen Sie den Geschwindigkeitsvergleich der BigQuery Storage API
Zusammenfassung der Verbindungsmethode nach DB von SQL Alchemy
Fünfäugige KI bei der Suche nach Monte-Carlo-Bäumen
Geschwindigkeitsvergleich von murmurhash3, md5 und sha1
[Statistik] Ich werde die Abtastung nach der Markov-Ketten-Monte-Carlo-Methode (MCMC) mit Animation erläutern.
#Monte Carlo-Methode zum Ermitteln des Umfangsverhältnisses mit Python
[Python3] Geschwindigkeitsvergleich usw. über den Entzug von numpy.ndarray
Eine Überprüfung der AWS SDK-Leistung nach Sprache
Versuchen Sie, die Monte-Carlo-Methode in Python zu implementieren