LINUX.ORG.RU

Переписать код на Java, чтобы он не тормозил и не жрал память

 ,


1

3

Хочу переписать свою поделку с унылого C++ на Java или даже сразу на Scala. В программе очень много операций над разными двумерными объектами, поэтому большая часть данных - это координаты на плоскости и их преобразования.

Решил проверить насколько быстро такие операции будут работать в в Java:

import java.util.ArrayList;
import java.util.List;

public class CalcVectors {
    private static class Vector2D {
        public final double x, y;

        private Vector2D(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public Vector2D add(Vector2D v) {
            return new Vector2D(x + v.x, y + v.y);
        }

        public Vector2D mult(Transform2D t) {
            return new Vector2D(x * t.cos - y * t.sin + t.tx,
                                y * t.sin + y * t.cos + t.ty);
        }

        @Override
        public String toString() {
            return "Vector2D(" + "x=" + x + ", y=" + y + ')';
        }
    }

    private static class Transform2D {
        public final double cos, sin, tx, ty;

        private Transform2D(double angle, double tx, double ty) {
            this.cos = Math.cos(angle);
            this.sin = Math.sin(angle);
            this.tx = tx;
            this.ty = ty;
        }
    }


    private static Vector2D calc(List<Vector2D> l, Transform2D t) {
        Vector2D res = new Vector2D(0, 0);
        for (Vector2D v : l) {
            res = res.add(v.mult(t));
        }
        return res;
    }

    private static void run(String str, List<Vector2D> list, Transform2D transf) {
        System.out.println("Start of " + str);
        Vector2D vector = null;
        int repeat = 1000;
        long started = System.nanoTime();
        for (int i = 0; i < repeat; ++i) {
            vector = calc(list, transf);
        }
        double totalTime = (System.nanoTime() - started)*1e-9;
        System.out.println("Res = " + vector);
        System.out.println("Total time = " + totalTime + " (sec)");
        System.out.println("Average time = " + totalTime/repeat + " (sec)");
        System.out.println("End of " + str);
    }

    public static void main(String[] args) {
        final int size = 1000000;
        List<Vector2D> list = new ArrayList<Vector2D>(size);
        for (int i = 0; i < size; ++i) {
            double d = (1.0*i)/size;
            list.add(new Vector2D(d, d));
        }
        Transform2D transf = new Transform2D(1.0, -2.5, 5.0);
        run("Warm Up", list, transf);
        System.out.println();
        run("Actual", list, transf);
    }
}
Запускаю вот так:
$ java -server -XX:+PrintCompilation CalcVectors
    208    1             java.lang.Object::<init> (1 bytes)
    210    2             java.util.ArrayList::add (29 bytes)
    220    3             java.util.ArrayList::ensureCapacityInternal (26 bytes)
    222    4             CalcVectors$Vector2D::<init> (7 bytes)
    222    5             CalcVectors$Vector2D::<init> (15 bytes)
    223    1 %           CalcVectors::main @ 12 (90 bytes)
    622    1 %           CalcVectors::main @ -2 (90 bytes)   made not entrant
Start of Warm Up
    630    6             java.util.ArrayList::access$100 (5 bytes)
    636    7             java.util.ArrayList$Itr::hasNext (20 bytes)
    639    8             java.util.ArrayList$Itr::next (66 bytes)
    642   10             java.util.ArrayList::access$200 (5 bytes)
    644    9             java.util.ArrayList$Itr::checkForComodification (23 bytes)
    652   11             CalcVectors$Vector2D::mult (56 bytes)
    656   12             CalcVectors$Vector2D::add (26 bytes)
    659    2 %           CalcVectors::calc @ 18 (54 bytes)
   1219   13             CalcVectors::calc (54 bytes)
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 32.180277053000005 (sec)
Average time = 0.03218027705300001 (sec)
End of Warm Up

Start of Actual
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 31.393999127 (sec)
Average time = 0.031393999127 (sec)
End of Actual
Видно, что на втором запуске JIT уже ничего докомпилировал. Получилось как-то заметно медленее, чем такой же вариант в C++:
#include <cmath>
#include <ctime>
#include <vector>
#include <iostream>

struct vector2d {
    double x, y;
    vector2d(double x = 0, double y = 0) : x(x), y(y) {}
};

vector2d operator+(const vector2d& v0, const vector2d& v1) {
    return vector2d(v0.x + v1.x, v0.y + v1.y);
}

struct transform2d {
    double cos, sin, tx, ty;
    transform2d(double angle, double tx, double ty)
    : cos(std::cos(angle)), sin(std::sin(angle)), tx(tx), ty(ty) {}
};

vector2d operator*(const vector2d& v, const transform2d& t) {
    double x = v.x*t.cos - v.y*t.sin + t.tx;
    double y = v.x*t.sin + v.y*t.cos + t.ty;
    return vector2d(x, y);
}

vector2d calc(const std::vector<vector2d>& vects, const transform2d& transf) {
    vector2d v;
    for (size_t i = 0; i < vects.size(); ++i) {
        v = v + vects[i]*transf;
    }
    return v;
}

int main() {
    std::vector<vector2d> vects(1000000);
    for (size_t i = 0; i < vects.size(); ++i) {
        double x = (1.0*i)/vects.size();
        vects[i] = vector2d(x, x);
    }
    transform2d tr(1.0, -2.5, 5.0);
    const int repeat = 1000;
    vector2d res;
    std::clock_t start = std::clock();
    for (int i = 0; i < repeat; ++i) {
        res = calc(vects, tr);
    }
    double total = ((double)(std::clock() - start))/CLOCKS_PER_SEC;
    std::cout << "Res = vector2d(" << res.x << "," << res.y << ")\n"
              << "Total time = " << total << " (sec)\n" 
              << "Average time = " << total/repeat << " (sec)" << std::endl;
}
Запуск C++:
$ ./a.out 
Res = vector2d(-2.65058e+06,5.69089e+06)
Total time = 8.52 (sec)
Average time = 0.00852 (sec)
Почти в 4 раза быстрее по сравнению с Java вариантом.

Кроме того, по памяти у Java также все гораздо хуже получилось: более 100Мб из кучи, в то время как C++ вариант 16Мб с копейками, что и ожидалось, т.к. один миллион структур vector2d как раз 16Мб и занимает.

Наверняка что-то сделал не так в Java варианте (ведь Java должна быть быстра почти как C++). Подскажите, как нужно правильно переписать Java вариант, чтобы приблизиться к C++?

★★★

В смысле скорости и памяти в дизайне масса грубых ошибок.

Подскажите, как нужно правильно переписать Java вариант, чтобы приблизиться к C++?

Качественных знаний из нескольких постов на LOR'е не получишь. Нужно нормально изучить язык и виртуальную машину. Лучше всего - по спецификациям Java и JVM. Тогда станут очевидными кучи тонкостей, позволяющие делать нормальный дизайн.

Если желания или возможности нет, тогда продолжит писаться подобный детский код.

ak380618
()

Хочу переписать свою поделку с унылого C++ на Java или даже сразу на Scala, чтобы он не тормозил и не жрал память

демонический смех в зале

dib2 ★★★★★
()
Ответ на: комментарий от bhfq

Доо, какой замечательный ответ, такая глубокая мысль, жалко что только бесполезный совсем.

Он бесполезен только для тех, кто хочет получить результат в сложной задаче как можно быстрее и как можно меньше напрягая мозг. Самообман, характерный для примитивно устроенных личностей.

ak380618
()

Тебе нужны 1 000 000 объектов Vector2D. Ты плодишь больше, чем 4 000 000 000. Ну ты понял, кто ты есть.

anonymous
()
Ответ на: комментарий от ak380618

Тогда станут очевидными кучи тонкостей, позволяющие делать нормальный дизайн.

Так я понимаю, что в JVM нет value-типов, и что в памяти данные лежат далеко не так компактно как в случае с C++. Именно про нормальный дизайн без потери абстракций (таких как Vector2D и Transform2D) и хотелось бы узнать.

kamre ★★★
() автор топика
Ответ на: комментарий от kamre

Так я понимаю, что в JVM нет value-типов, и что в памяти данные лежат далеко не так компактно как в случае с C++.

Вот он правильно тебе сказал, тебе

Нужно нормально изучить язык и виртуальную машину.

anonymous
()
Ответ на: комментарий от anonymous

Ты плодишь больше, чем 4 000 000 000.

А как в Java делают по-другому? У нее же сверх-быстрый аллокатор и GC, который очень коротко живущие поколения должен мгновенно собирать. А также есть escape analysis, который может вообще аллокации с хипа убирать. Почему все это не работает на моем примере?

kamre ★★★
() автор топика
Ответ на: комментарий от anonymous

Нужно нормально изучить язык и виртуальную машину.

Предлагается все самому вручную заинлайнить в методе calc, да еще и на массив double перейти? Или в чем суть?

Почему hotspot не может полностью заинлайнить код в calc и убрать все не нужные аллокации совсем?

kamre ★★★
() автор топика

Ну вообще, в Жабе когда хотят сложить или перемножить float'ы или double'ы, то берут float'ы или double'ы и складывают их либо умножают, а не создают под это классы. В C++ компилятор твои struct'ы, скорее всего, оптимизирует до буквально простых структур, а в Java полноценные объекты создаются в куче.

proud_anon ★★★★★
()
Ответ на: комментарий от kamre

заинлайнить

Вы так говорите, как будто речь идёт о превращении кода в нечитаемый, а не о простом рефакторинге.

Почему hotspot не может полностью заинлайнить код в calc и убрать все не нужные аллокации совсем?

Ну, не всегда можно положиться на оптимизатор, что ж сделаешь. Тем более, когда участвуют генерики вместо обычных массивов.

proud_anon ★★★★★
()
Ответ на: комментарий от kamre

Предлагается все самому вручную заинлайнить в методе calc, да еще и на массив double перейти?

Предлагается не плодить объекты. Как ты этого добъёшься, это твоя проблема. Если ты - обезьяна, то заинлайни и перейди на массив int, так будет быстрее, ага.

Или в чем суть?

Вот в этом:

Нужно нормально изучить язык и виртуальную машину.

anonymous
()

Берёшь свой код, ищешь в нём new так или иначе вызываемые в цикле. Ищешь способ от них избавиться. Например вместо vec3 = vec1.add(vec2) реfuckторишь на vec3.set(vec1), vec3.add(vec2).

PolarFox ★★★★★
()
Ответ на: комментарий от proud_anon

Вы так говорите, как будто речь идёт о превращении кода в нечитаемый, а не о простом рефакторинге.

Конечно в нечитаемый, ведь в коде нужны высокоуровневые операции над объектами предметной области (векторами/матрицами/...), а не пачка нечитаемых формул на пол экрана (которые должен будет в итоге сгенерировать компилятор где-то там у себя внутри).

Как в Java решается эта задача?

kamre ★★★
() автор топика
Ответ на: комментарий от anonymous

Как ты этого добъёшься, это твоя проблема.

Нужно нормально изучить язык и виртуальную машину.

Хотелось бы от знатоков, «нормально изучивших язык и виртуальную машину», увидеть как решается проблема в самом простом случае вроде того, что я привел.

kamre ★★★
() автор топика
Ответ на: комментарий от PolarFox

Например вместо vec3 = vec1.add(vec2) реfuckторишь на vec3.set(vec1), vec3.add(vec2).

Предлагается сделать mutable классы и начинать делать defensive copies, когда нужно передавать «наружу» свойства более сложных объектов?

kamre ★★★
() автор топика
Ответ на: комментарий от proud_anon

C++ компилятор твои struct'ы, скорее всего, оптимизирует до буквально простых структур

Что имеется ввиду? Они и так сразу «буквально простые структуры», разве нет?

kamre ★★★
() автор топика
Ответ на: комментарий от kamre

Предлагается не аллоцировать объектов больше, чем необходимо. Если хочешь иммутабельности и чистоты, то тебе нужны уж точно не Java и не C++.

PolarFox ★★★★★
()
Ответ на: комментарий от kamre

Хотелось бы от знатоков, «нормально изучивших язык и виртуальную машину», увидеть как решается проблема в самом простом случае вроде того, что я привел.

Держи. Там решения многих проблем с двумерными объектами в самых простых случаях, исходники от гуру джавы прилогаются.

anonymous
()
Ответ на: комментарий от anonymous

исходники от гуру джавы прилогаются

У этих гуру все mutable, в результате все нетривиальные выражения над объектами нужно вручную разбивать на отдельные подвыражения. Т.е. что-то вроде

vector2d dir = pos + (end - start)*transf1*transf2;
с кучей промежуточных результатов уже не написать.

Кроме того придется создавать defensive copy в случаях, когда возвращается такой mutable объект, или же аккуратно следить, чтобы вызывающий код ничего не менял и сам создавал копии.

kamre ★★★
() автор топика

Переделал на такой вариант:

public class CalcVectors {
    private static class Vector2D {
        public double x, y;

        private Vector2D(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public Vector2D add(Vector2D v) {
            x += v.x;
            y += v.y;
            return this;
        }

        public Vector2D mult(Transform2D t) {
            double x1 = x * t.cos - y * t.sin + t.tx;
            double y1 = y * t.sin + y * t.cos + t.ty;
            x = x1;
            y = y1;
            return this;
        }

        @Override
        public String toString() {
            return "Vector2D(" + "x=" + x + ", y=" + y + ')';
        }
    }

    private static class Transform2D {
        public double cos, sin, tx, ty;

        private Transform2D(double angle, double tx, double ty) {
            this.cos = Math.cos(angle);
            this.sin = Math.sin(angle);
            this.tx = tx;
            this.ty = ty;
        }
    }

    private static class VectorOfVector2D {
        private double[] buffer;
        private int size;

        private VectorOfVector2D(int size) {
            this.size = size;
            buffer = new double[2 * size];
        }

        public Vector2D get(int idx) {
            return new Vector2D(buffer[idx * 2], buffer[idx * 2 + 1]);
        }

        public void set(int idx, Vector2D v) {
            buffer[2 * idx] = v.x;
            buffer[2 * idx + 1] = v.y;
        }

        public int length() {
            return size;
        }
    }

    private static Vector2D calc(VectorOfVector2D v, Transform2D t) {
        Vector2D res = new Vector2D(0, 0);
        for (int i = 0; i < v.length(); ++i) {
            res.add(v.get(i).mult(t));
        }
        return res;
    }

    private static void run(String str, VectorOfVector2D vects, Transform2D transf) {
        System.out.println("Start of " + str);
        Vector2D vector = null;
        int repeat = 1000;
        long started = System.nanoTime();
        for (int i = 0; i < repeat; ++i) {
            vector = calc(vects, transf);
        }
        double totalTime = (System.nanoTime() - started) * 1e-9;
        System.out.println("Res = " + vector);
        System.out.println("Total time = " + totalTime + " (sec)");
        System.out.println("Average time = " + totalTime / repeat + " (sec)");
        System.out.println("End of " + str);
    }

    public static void main(String[] args) {
        final int size = 1000000;
        VectorOfVector2D vects = new VectorOfVector2D(size);
        for (int i = 0; i < size; ++i) {
            double d = (1.0 * i) / size;
            vects.set(i, new Vector2D(d, d));
        }
        Transform2D transf = new Transform2D(1.0, -2.5, 5.0);
        run("Warm Up", vects, transf);
        System.out.println();
        run("Actual", vects, transf);
    }
}
Гораздо лучше стал работать:
$java -server -XX:+PrintCompilation CalcVectors
    198    1             java.lang.Object::<init> (1 bytes)
    200    2             CalcVectors$Vector2D::<init> (7 bytes)
    209    3             CalcVectors$Vector2D::<init> (15 bytes)
    211    4             CalcVectors$VectorOfVector2D::set (27 bytes)
    213    1 %           CalcVectors::main @ 16 (92 bytes)
    240    1 %           CalcVectors::main @ -2 (92 bytes)   made not entrant
Start of Warm Up
    253    5             CalcVectors$VectorOfVector2D::length (5 bytes)
    256    6             CalcVectors$VectorOfVector2D::get (27 bytes)
    257    7             CalcVectors$Vector2D::mult (64 bytes)
    262    8             CalcVectors$Vector2D::add (28 bytes)
    263    2 %           CalcVectors::calc @ 13 (43 bytes)
    290    9             CalcVectors::calc (43 bytes)
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 7.934098328 (sec)
Average time = 0.007934098328000001 (sec)
End of Warm Up

Start of Actual
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 7.874191606 (sec)
Average time = 0.007874191606 (sec)
End of Actual
И памяти стало чуть больше 20Мб жрать, почти нормально.

kamre ★★★
() автор топика
Последнее исправление: kamre (всего исправлений: 1)
Ответ на: комментарий от kamre

Кроме того придется создавать defensive copy в случаях, когда возвращается такой mutable объект, или же аккуратно следить, чтобы вызывающий код ничего не менял и сам создавал копии.

Сделай два варианта - Vector2D и MutableVector2D и в середине вычислений используй Mutable

maxcom ★★★★★
()
Ответ на: комментарий от kamre
       public Vector2D get(int idx) {
            return new Vector2D(buffer[idx * 2], buffer[idx * 2 + 1]);
        }

вот этот get еще убери. Сделай интерфейс для Vector2D и как одну из реализаций ту что вытаскивает его из массива по сохраненному внутри смещению

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Сделай два варианта - Vector2D и MutableVector2D и в середине вычислений используй Mutable

Тоже вариант, но пока, думаю, буду следить и не портить данные из вызывающих методов.

вот этот get еще убери

Вроде как раз на таких get срабатывает escape analysis.

Сделай интерфейс для Vector2D и как одну из реализаций ту что вытаскивает его из массива по сохраненному внутри смещению

Интересный вариант, надо попробовать.

kamre ★★★
() автор топика

Для твоего кода нормальная производительность. Если хочешь аналога плюсов — используй массивы даблов, откажись от создания кучи объектов и т.д., код будет некрасивым, но быстрее.

Legioner ★★★★★
()
Ответ на: комментарий от maxcom

Сделай два варианта - Vector2D и MutableVector2D и в середине вычислений используй Mutable

у меня с таким подходом в 2 раза быстрее стало выполняться
Было: 10.01 sec
Стало: 4.93 sec

kovrik ★★★★★
()

Переписать код на Java, чтобы он не тормозил и не жрал память

Взаимоисключающие параграфы. Это такой тонкий вброс на день программиста?

m0rph ★★★★★
()

Warmup > 10000 раз (а то и 15000).

И да, иммутабельные обьекты и остальные хорошие практики не такие уж хорошие когда нужно молотить тонны чисел. Сам подумай как выглядел бы ассемблерный код где ты в цикле что-то умножаешь и суммируешь - элементарно. А теперь представь что туда вставили хоть сколько угодно эффективную муть с аллокатором. Да будь он хоть волшебным, это будет большое замедление.

В С++ варианте нет динамической памяти вообще, элементарнейшее выделение памяти на стеке

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 2)

Чтобы ускорить код на c++, можно воспользоваться возможностями SIMD.

nerdogeek
()

один миллион структур vector2d

структур

В Java нет поддержки пользовательских value типов - используйте C#. Все может быть гораздо быстрее, если про ваши объекты GC знать не будет и они будут просто в стеке создаваться (то есть они должны быть как struct объявлены). А если возьмете Скалу и перепишете в функциональном стиле с иммутабельностями - будет чуть ли не хуже.

eternity
()
Ответ на: комментарий от m0rph

Пятница же, товарищ уже отмечает.

anonymous
()

Вот тут обсуждается. Кажется что нужно чтобы обьект оставался в одном stack frame, но у тебя вроде так и есть

http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html

Хочешь узнать точно, собери Debug JVM и включи опции распечатки Escape Analisys

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)

Унылый c++ в лице clang 3.3 показал 2.2 sec.

Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 13.1.1.171 Build 20130313

Res = vector2d(-2.65058e+006,5.69089e+006)
Total time = 2.449 (sec)
Average time = 0.002449 (sec)

Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64

Res = vector2d(-2.65058e+006,5.69089e+006)
Total time = 5.632 (sec)
Average time = 0.005632 (sec)

gcc версия 4.8.1 20130603 (Red Hat 4.8.1-1) (GCC)

Res = vector2d(-2.65058e+06,5.69089e+06)
Total time = 5.05 (sec)
Average time = 0.00505 (sec)

clang version 3.3 (tags/RELEASE_33/rc3)

Res = vector2d(-2.65058e+06,5.69089e+06)
Total time = 2.2 (sec)
Average time = 0.0022 (sec)

bhfq ★★★★★
()
Ответ на: Унылый c++ в лице clang 3.3 показал 2.2 sec. от bhfq

Мой мир перевернулся, Microsoft компилятор отстает от GCC. Раньше как тузик тряпку рвал. Все, ждем массового вымирания волков в лесу и птиц разбивающихся о землю.

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)
Ответ на: комментарий от vertexua

тем не менее gcc без -fPIC

 g++ -O2 -m64 cpptest.cpp 

 ./a.out 
Res = vector2d(-2.65058e+06,5.69089e+06)
Total time = 2.29 (sec)
Average time = 0.00229 (sec)
bhfq ★★★★★
()
Ответ на: комментарий от vertexua

Сам подумай как выглядел бы ассемблерный код где ты в цикле что-то умножаешь и суммируешь - элементарно. А теперь представь что туда вставили хоть сколько угодно эффективную муть с аллокатором. Да будь он хоть волшебным, это будет большое замедление.

Можно все операции над объектами заинлайнить и увидеть, что ни один аллоцированный объект не уходит за пределы метода, а значит все аллокации можно убирать и делать вычисления в регистрах/на стеке. Странно, что escape analysis на таком простом примере не работает.

kamre ★★★
() автор топика
Ответ на: комментарий от m0rph

Взаимоисключающие параграфы.

Ну да, название топика неоднозначное получилось :) Имелось ввиду то, что у меня есть код на Java и его нужно переписать таким образом, чтобы он не особо тормозил и не жрал память по сравнению с вариантом на c++.

kamre ★★★
() автор топика

Поэкспериментировав, выяснил, что:

  • Можно срезать секунды четыре, перейдя с List на массив Vector2D.
  • Можно срезать ещё секунды две, перейдя на Java 8. При этом на Java 8 почти не отличается время Warm Up и Actual.


Сейчас попробую переписать на массив double'ов.

proud_anon ★★★★★
()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от kamre

У меня все в виртуалках, по этому вот в оной с макосью:

java -server CalcVectors
Start of Warm Up
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 2.7488270000000004 (sec)
Average time = 0.0027488270000000006 (sec)
End of Warm Up

Start of Actual
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 2.718065 (sec)
Average time = 0.002718065 (sec)
End of Actual

И виндой

java -server CalcVectors
Start of Warm Up
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 2.7417080240000002 (sec)
Average time = 0.002741708024 (sec)
End of Warm Up

Start of Actual
Res = Vector2D(x=-2650584.18888554, y=5690885.954451363)
Total time = 2.721376809 (sec)
Average time = 0.002721376809 (sec)
End of Actual

bhfq ★★★★★
()
Ответ на: комментарий от kamre

Так я же переписал выше на массив, или что-то другое имеется ввиду?

Ой. Я и не заметил. Ну, вот и хорошо. На моей машине на Java 8 даёт чуть меньше 5 секунд, правда, больше, чем C++.

proud_anon ★★★★★
()

блин как вы на этом пишите?!

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
import Data.Vector.Unboxed as U
import Data.Foldable as F
import Data.Array.Repa.IO.Timing
import Control.Exception

size = 1000000;

-- Transform
data Transform = Transform Double Double Double Double

transform2d x y z = Transform (cos x) (sin x) y z

-- Vector
type V = (Double, Double)

mult :: Transform -> V -> V
mult (Transform cs ss x y) (vx,vy) = (vx*cs - vy*ss+x, vy*cs+vx*ss+y)

add :: V -> V -> V
add (vx1,vy1) (vx2,vy2) = (vx1+vx2, vy1+vy2)

main = do
    let vec = U.generate size (\i -> let d = (fromIntegral i)/(fromIntegral size) in (d,d))
        tf = transform2d 1 (-2.5) 5
    let repeat = 1000;
    (v,t) <- time$ replicateM repeat $ evaluate $ U.foldr1' (\y x -> x `add` (mult tf) y) vec
    putStr $ prettyTime t

----
qnikst@thinkpad ~/tmp/lor/2d $ ./1 
elapsedTimeMS   = 85
cpuTimeMS       = 80
qnikst ★★★★★
()
Последнее исправление: qnikst (всего исправлений: 2)

Вы оцениваете производительность java программы из консоли ? о_О снимаю шляпу! Хахахах))))))))))

ii8_ ★★★★
()
Ответ на: комментарий от qnikst

Что это за помесь си с бейсиком?

anonymous
()
Ответ на: комментарий от ii8_

Вы оцениваете производительность java программы из консоли ?

А как тогда нужно, если не из консоли?

kamre ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.