Залез на shootout — решил сравнить C# и N. Содрал тесты для C#, перегнал их cs2n, стал смотреть и мерять. Вот из этого
using System;
class NSieve
{
static int nsieve(int m, bool[] isPrime) {
for (int i=2; i <= m; i++) isPrime[i] = true;
int count = 0;
for (int i=2; i <= m; i++){
if (isPrime[i]){
for (int k=i+i; k <= m; k+=i) isPrime[k] = false;
count++;
}
}
return count;
}
public static void Main(String[] args)
{
int n = 2;
if (args.Length > 0) n = Int32.Parse(args[0]);
if (n < 2) n = 2;
int m = (1<<n)*10000;
bool[] flags = new bool[m+1];
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m,flags));
m = (1<<n-1)*10000;
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m,flags));
m = (1<<n-2)*10000;
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m,flags));
}
}
получилось вот это
using System;
class NSieve
{
static nsieve(m : int, isPrime : array [bool]) : int {
for (mutable i=2; i <= m; i++) isPrime[i] = true;
mutable count = 0;
for (mutable i=2; i <= m; i++){
when (isPrime[i]){
for (mutable k=i+i; k <= m; k+=i) isPrime[k] = false;
count++;
}
}
count;
}
public static Main(args : array [String]) : void
{
mutable n = 2;
when (args.Length > 0) n = Int32.Parse(args[0]);
when (n < 2) n = 2;
mutable m = (1<<n)*10000;
def flags = array(m+1);
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m,flags));
m = (1<<n-1)*10000;
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m,flags));
m = (1<<n-2)*10000;
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m,flags));
}
}
(а для N ещё нет оформления кода?
)
Различие в скорости получилось мизерным: для аргумента 12 при общем времени выполнения теста ~8 сек. разница составила в среднем 0.03 — 0.05 с. на моей машине в пользу C#.
Интересует — как не меняя сути алгоритма переписать тест для большей выразительности/лаконичности кода? Может и в скорости чуть подтянемся?
P.S. Portable.NET "продул" моно почти в полтора раза — > 11 сек. против 8. NET-а от M$ нет — сравнить не могу
P.P.S. Хм, если снести массив внутрь функции и переписать логику с учётом инициализации в N массива по умолчанию:
using System;
class NSieve
{
static nsieve(mutable m : int) : int {
def isPrime = array(m+1) : array [bool];
mutable count = 0;
for (mutable i=2; i <= m; i++){
unless (isPrime[i]){
for (mutable k=i+i; k <= m; k+=i) isPrime[k] = true;
count++;
}
}
count;
}
public static Main(mutable args : array [String]) : void
{
mutable n = 2;
when (args.Length > 0) n = Int32.Parse(args[0]);
when (n < 2) n = 2;
mutable m = (1<<n)*10000;
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m));
m = (1<<n-1)*10000;
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m));
m = (1<<n-2)*10000;
Console.WriteLine("Primes up to {0,8:D} {1,8:D}", m, nsieve(m));
}
}
уже получим выигрыш N, но опять совсем незначительный — ~0.2 с (три прохода по массиву?)
P.P.P.S. Просьба не ругаться за то, что маюсь разной х..нёй
P.P.P.P.S. С аргументом 14 выигрыш N составил ~0,8 с, но это всё в пределах погрешности, ибо на двух десятках итераций разница между максимальным и минимальным временем более 10%