Благодарим @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);
}
}
+1 к записи Вашего собственного exp () реализация. Таким образом, если это - действительно узкое место в Вашем приложении. Если можно иметь дело с небольшой погрешностью, существует много чрезвычайно эффективных алгоритмов оценки экспоненты там, некоторые из них датирующийся века. Насколько я понимаю exp Java () реализация является довольно медленной, даже для алгоритмов, которые должны возвратить "точные" результаты.
О, и не бойтесь записать что exp () реализация в чистом Java. JNI имеет много издержек, и JVM может оптимизировать байт-код во времени выполнения иногда даже вне того, чего C/C++ может достигнуть.
Я выполняю алгоритм подбора, и минимальная ошибка подходящего результата является путем, больше, чем точность 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).
Существуют более быстрые алгоритмы для exp в зависимости от какой your'e, пытающийся выполнять. Пространство задач, ограниченное определенным диапазоном, сделайте Вам только нужны определенное разрешение, точность или точность, и т.д.
При определении проблемы очень хорошо можно найти, что можно использовать таблицу с интерполяцией, например, который унесет почти любой другой алгоритм из воды.
Какие ограничения можно обратиться к exp для получения того компромисса производительности?
- Adam
Существует стоимость, связанная с вызовом через границу JNI.
Если Вы могли бы переместить цикл, который называет exp () в собственный код также, так, чтобы был всего один собственный вызов, то Вы могли бы получить лучшие результаты, но я сомневаюсь, что это будет значительно быстрее, чем чистое решение для Java.
Я не знаю детали Вашего приложения, но если у Вас есть довольно ограниченный набор возможных аргументов в пользу вызова, Вы могли бы использовать предварительно вычисленную справочную таблицу, чтобы заставить Ваш Java кодировать быстрее.
Запишите свое собственное, адаптированный к Вашим потребностям.
Например, если все Ваши экспоненты имеют питание два, можно использовать смещение бита. Если Вы работаете с ограниченным диапазоном или множеством значений, можно использовать справочные таблицы. Если Вы не должны точно определять точность, Вы используете неточное, но быстрее, алгоритм.
Существуют просто издержки, связанные с использованием JNI, см. также: http://java.sun.com/docs/books/performance/1st_edition/html/JPNativeCode.fm.html
Таким образом, поскольку другие предложили попытку сопоставить операции, которые включили бы использование JNI.
Проблемой с использованием JNI являются издержки, вовлеченные в совершение звонка к JNI. Виртуальная машина Java довольно оптимизирована в эти дни и звонит во встроенный Math.exp (), автоматически оптимизированы для вызова прямо через в C exp () функция, и они могли бы даже быть оптимизированы в прямые x87 инструкции по сборке с плавающей точкой.
Реальный вопрос, это стало горлышком бутылки для Вас? Вы представили свое приложение и нашли, что это, чтобы быть главной причиной замедляется?
В противном случае я рекомендовал бы использовать версию Java. Попытайтесь не предварительно оптимизировать, поскольку это просто вызовет разработку, замедляются. Можно потратить расширенное количество времени на проблему, которая не может быть проблемой.
Однако я думаю, что Ваш тест дал Вам Ваш ответ. Если jni + C медленнее, используйте версию Java.
Вы смогли заставлять это работать быстрее, если Вы делаете их в пакетах. Совершение звонка JNI добавляет наверху, таким образом, Вы не хотите делать это для каждого exp (), необходимо вычислить. Я попытался бы передать массив 100 значений и заставить результаты видеть, помогает ли он производительности.
Используйте Java.
Кроме того, результаты кэша exp и затем можно искать ответ быстрее, чем вычисление их снова.
Вы хотели бы перенестись безотносительно вызова цикла Math.exp()
в C также. Иначе издержки маршалинга между Java и C сокрушат любое преимущество производительности.
Это уже несколько раз требовали (см., например, здесь). Вот приближение к 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 () на моей машине, но это может варьироваться решительно, если Вы компилируете с - сервер.
Так как код Java будет скомпилирован в собственный код со своевременным (JIT) компилятором, нет действительно никакой причины использовать JNI для вызова собственного кода.
Кроме того, Вы не должны кэшировать результаты метода, где входные параметры являются вещественными числами с плавающей точкой. Усиления, полученные вовремя, будут очень потеряны в количестве использованного пространства.