быстрее Math.exp () через JNI?

Благодарим @odeToCode за ответ. Ради полноты я повторно разместил его комментарий как ответ с моим (рабочим) примером. Магия - это атрибут [FromServices].

public class CreateDynamicMappingProfileViewModel : IValidatableObject
{

    [Display(Name = "Name", Order = 1), Required, MaxLength(50, ErrorMessage = "The name field allows a maximum of 50 characters")]
    public string Name { get; set; }

    [Display(Name = "Data Format", Order = 2), Required]
    public DataFormat DataFormat { get; set; }

    [Display(Name = "Data Context", Order = 3), Required]
    public DataContextType DataContextType { get; set; }

    [FromServices]
    public IMappingProfileServices MappingProfileServices { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        IMappingProfile mappingProfile = new DynamicMappingProfile(Name, DataFormat, DataContextType);
        return MappingProfileServices.ValidateCanSave(mappingProfile);
    }
}
10
задан Noam M 2 June 2015 в 19:25
поделиться

13 ответов

+1 к записи Вашего собственного exp () реализация. Таким образом, если это - действительно узкое место в Вашем приложении. Если можно иметь дело с небольшой погрешностью, существует много чрезвычайно эффективных алгоритмов оценки экспоненты там, некоторые из них датирующийся века. Насколько я понимаю exp Java () реализация является довольно медленной, даже для алгоритмов, которые должны возвратить "точные" результаты.

О, и не бойтесь записать что exp () реализация в чистом Java. JNI имеет много издержек, и JVM может оптимизировать байт-код во времени выполнения иногда даже вне того, чего C/C++ может достигнуть.

12
ответ дан 3 December 2019 в 13:37
поделиться

Я выполняю алгоритм подбора, и минимальная ошибка подходящего результата является путем, больше, чем точность Math.exp ().

Трансцендентные функции всегда намного более медленнее, чем дополнение или умножение и известное узкое место. Если Вы знаете, что Ваши значения находятся в узком диапазоне, можно просто создать справочную таблицу (Два сортированных массива; один вход, один вывод). Используйте Arrays.binarySearch, чтобы найти корректный индекс и интерполировать значение с элементами в [индексе] и [index+1].

Другой метод должен разделить число. Позволяет берут, например, 3.81 и разделяют это в 3+0.81. Теперь Вы умножаете e = 2.718 три раза и добираетесь 20.08.

Теперь к 0,81. Все значения между 0 и 1 сходятся быстро с известным экспоненциальным рядом

1+x+x^2/2+x^3/6+x^4/24.... и т.д.

Возьмите столько условия, сколько Вам нужно для точности; к сожалению, это медленнее, если x приближается 1. Позволяет говорят, что Вы переходите к x^4, затем Вы добираетесь 2.2445 вместо корректных 2.2448

Затем умножьте результат 2.781^3 = 20.08 с 2.781^0.81 = 2.2445, и у Вас есть результат 45.07 с ошибкой одной части две тысячи (корректный: 45.15).

0
ответ дан 3 December 2019 в 13:37
поделиться

Существуют более быстрые алгоритмы для exp в зависимости от какой your'e, пытающийся выполнять. Пространство задач, ограниченное определенным диапазоном, сделайте Вам только нужны определенное разрешение, точность или точность, и т.д.

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

Какие ограничения можно обратиться к exp для получения того компромисса производительности?

- Adam

0
ответ дан 3 December 2019 в 13:37
поделиться

Существует стоимость, связанная с вызовом через границу JNI.

Если Вы могли бы переместить цикл, который называет exp () в собственный код также, так, чтобы был всего один собственный вызов, то Вы могли бы получить лучшие результаты, но я сомневаюсь, что это будет значительно быстрее, чем чистое решение для Java.

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

0
ответ дан 3 December 2019 в 13:37
поделиться

Запишите свое собственное, адаптированный к Вашим потребностям.

Например, если все Ваши экспоненты имеют питание два, можно использовать смещение бита. Если Вы работаете с ограниченным диапазоном или множеством значений, можно использовать справочные таблицы. Если Вы не должны точно определять точность, Вы используете неточное, но быстрее, алгоритм.

0
ответ дан 3 December 2019 в 13:37
поделиться

Существуют просто издержки, связанные с использованием JNI, см. также: http://java.sun.com/docs/books/performance/1st_edition/html/JPNativeCode.fm.html

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

0
ответ дан 3 December 2019 в 13:37
поделиться

Проблемой с использованием JNI являются издержки, вовлеченные в совершение звонка к JNI. Виртуальная машина Java довольно оптимизирована в эти дни и звонит во встроенный Math.exp (), автоматически оптимизированы для вызова прямо через в C exp () функция, и они могли бы даже быть оптимизированы в прямые x87 инструкции по сборке с плавающей точкой.

0
ответ дан 3 December 2019 в 13:37
поделиться

Реальный вопрос, это стало горлышком бутылки для Вас? Вы представили свое приложение и нашли, что это, чтобы быть главной причиной замедляется?

В противном случае я рекомендовал бы использовать версию Java. Попытайтесь не предварительно оптимизировать, поскольку это просто вызовет разработку, замедляются. Можно потратить расширенное количество времени на проблему, которая не может быть проблемой.

Однако я думаю, что Ваш тест дал Вам Ваш ответ. Если jni + C медленнее, используйте версию Java.

2
ответ дан 3 December 2019 в 13:37
поделиться

Вы смогли заставлять это работать быстрее, если Вы делаете их в пакетах. Совершение звонка JNI добавляет наверху, таким образом, Вы не хотите делать это для каждого exp (), необходимо вычислить. Я попытался бы передать массив 100 значений и заставить результаты видеть, помогает ли он производительности.

3
ответ дан 3 December 2019 в 13:37
поделиться

Используйте Java.

Кроме того, результаты кэша exp и затем можно искать ответ быстрее, чем вычисление их снова.

6
ответ дан 3 December 2019 в 13:37
поделиться

Вы хотели бы перенестись безотносительно вызова цикла Math.exp() в C также. Иначе издержки маршалинга между Java и C сокрушат любое преимущество производительности.

5
ответ дан 3 December 2019 в 13:37
поделиться

Это уже несколько раз требовали (см., например, здесь). Вот приближение к Math.exp (), скопировано с этого сообщения в блоге:

public static double exp(double val) {
    final long tmp = (long) (1512775 * val + (1072693248 - 60801));
    return Double.longBitsToDouble(tmp << 32);
}

Это - в основном то же как справочная таблица с записями 2048 года и линейной интерполяцией между записями, но всем этим с приемами плавающей точки IEEE. В 5 раз быстрее, чем Math.exp () на моей машине, но это может варьироваться решительно, если Вы компилируете с - сервер.

15
ответ дан 3 December 2019 в 13:37
поделиться

Так как код Java будет скомпилирован в собственный код со своевременным (JIT) компилятором, нет действительно никакой причины использовать JNI для вызова собственного кода.

Кроме того, Вы не должны кэшировать результаты метода, где входные параметры являются вещественными числами с плавающей точкой. Усиления, полученные вовремя, будут очень потеряны в количестве использованного пространства.

0
ответ дан 3 December 2019 в 13:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: