2014-10-19 3 views
5

Я написал простую функцию для вычисления простых чисел в D. Я думал, что это довольно быстро, вычисляя простые числа до 100 000. Но потом я хотел сравнить его с NodeJS. Когда я впервые запускал NodeJS-скрипт, я был поражен различием и дважды проверял, что я не пропустил какой-то расчет каким-то образом. Но эти два довольно функционально идентичны.NodeJS быстрее, чем D при вычислении простых чисел. Как?

D:

import std.stdio; 
import std.math; 
import std.datetime; 
import std.file; 
import std.array; 

enum size_t ITERATIONS = 100_000; 

bool divisible(real n) { 
    real d; 
    for(d = 3; d < floor(n/2); d += 2) { 
     if(n % d == 0) { 
      return true; 
     } 
    } 

    return false; 
} 

void main() { 
    StopWatch sw; 
    size_t T = ITERATIONS; 
    size_t C = 0; 
    real n = 2; 
    real r[ITERATIONS]; 
    r[C] = n; 
    sw.start(); 
    C++; 
    for(n = 3; n < T; n += 2) { 
     if(!divisible(n)) { 
      r[C] = n; 
      C++; 
     } 
    } 

    sw.stop(); 
    double seconds = cast(double)sw.peek().usecs/1_000_000; 
    writeln("\n\n", C, " prime numbers calculated in ", seconds, " seconds."); 


    File file = File("primes.txt", "w"); 
    file.writeln("\n", C, " prime numbers calculated ", seconds, " seconds."); 

    foreach(number; r[0..C]) { 
     file.writeln(number); 
    } 

    file.writeln("\n", "end"); 
    file.close(); 
} 

NodeJS:

var fs = require('fs'); 

var ITERATIONS = 100000; 

function divisible(n) { 
    var d; 
    for(d = 3; d < Math.floor(n/2); d += 2) { 
     if(n % d == 0) { 
      return true; 
     } 
    } 

    return false; 
} 

(function() { 
    var buffer = [ ], 
     now  = Date.now(), 
     C  = 0 
     n  = 2 
     ; 

    buffer.push(n); 
    C++; 
    for(n = 3; n < ITERATIONS; n += 2) { 
     if(!divisible(n)) { 
      buffer.push(n); 
      C++; 
     } 
    } 

    var time = Date.now() - now, 
     seconds = time/1000 
     ; 

    console.log("\n\n", C, " prime numbers calculated. Process took ", seconds, " seconds."); 
    buffer.push("\n" + C + " prime numbers calculated. Process took " + seconds + " seconds."); 

    fs.writeFile("node_primes.txt", buffer.join("\n"), function(err) { 
     if(err) throw err; 

     console.log("Primes have been written to file."); 
    }); 
})(); 

Результаты:

Calculating 100,000 primes: 
D:  3.49126 seconds 
NodeJS: 0.652 seconds 

Может кто-нибудь объяснить, почему это происходит?

Заранее спасибо.

+0

компилятор и командная строка для D? –

+0

Я использую 'dmd/path/to/source.d' для компиляции. – thephpdev

+0

Попробуйте использовать 'dmd -O -release -inline -boundscheck = off/path/to/source.d'. –

ответ

7

При ненужном объявлении переменных как real вы являетесь , заставляя арифметику с плавающей запятой, где может использоваться целочисленная арифметика. Заменить все экземпляры real с int, чтобы избавиться от этой floor() и ваша D программа будет работать так же быстро, как версия Node.js:

import std.stdio; 
import std.math; 
import std.datetime; 
import std.file; 
import std.array; 

enum size_t ITERATIONS = 100_000; 

bool divisible(int n) { 
    int d; 
    for(d = 3; d < n/2; d += 2) { 
     if(n % d == 0) { 
      return true; 
     } 
    } 

    return false; 
} 

void main() { 
    StopWatch sw; 
    size_t T = ITERATIONS; 
    size_t C = 0; 
    int n = 2; 
    int r[ITERATIONS]; 
    r[C] = n; 
    sw.start(); 
    C++; 
    for(n = 3; n < T; n += 2) { 
     if(!divisible(n)) { 
      r[C] = n; 
      C++; 
     } 
    } 

    sw.stop(); 
    double seconds = cast(double)sw.peek().usecs/1_000_000; 
    writeln("\n\n", C, " prime numbers calculated in ", seconds, " seconds."); 


    File file = File("primes.txt", "w"); 
    file.writeln("\n", C, " prime numbers calculated ", seconds, " seconds."); 

    foreach(number; r[0..C]) { 
     file.writeln(number); 
    } 

    file.writeln("\n", "end"); 
    file.close(); 
} 
+0

Это, должно быть, поразило муха. Я пробовал этот код против Node.js и получил около 1.8 ускорения. –

+0

Привет, это решило. Я не знал, что использование real - это принудительное использование операций с плавающей запятой. Но интересно, что удаление Math.floor() из NodeJS заставило его запустить 0,12 секунды медленнее avg .. – thephpdev

+0

'real' в D определяется как тип с плавающей точкой с наибольшей точностью. Это означает, что это потенциально самый медленный тип номера, который вы могли бы выбрать. С другой стороны, среда выполнения V8 может выполнять оптимизацию при числовых операциях. Например, он может использовать целочисленные операции, когда известно, что используются целые числа. –