Я искал эффективный подход для расчета б (скажем, a = 2
и b = 50
). Для начала я решил взглянуть на реализацию Math.Pow()
функции. Но в .NET Reflector все, что я нашел, было так:
[MethodImpl(MethodImplOptions.InternalCall), SecuritySafeCritical]
public static extern double Pow(double x, double y);
Каковы некоторые из ресурсов, в которых я могу видеть, что происходит внутри, когда я вызываю Math.Pow()
функцию?
InternalCall
сextern
модификатором (так как они кажутся противоречивыми), пожалуйста, посмотрите вопрос (и полученные ответы), который я разместил об этой самой вещи.2^x
операции, еслиx
целое число, результатом является операция сдвига. Поэтому, возможно, вы могли бы построить результат, используя мантиссу2
и показатель степениx
.Ответы:
Это означает, что метод фактически реализован в CLR, написанном на C ++. Компилятор Just-in-Time обращается к таблице с внутренне реализованными методами и напрямую компилирует вызов функции C ++.
Для просмотра кода требуется исходный код CLR. Вы можете получить это из дистрибутива SSCLI20 . Он был написан в течение периода времени .NET 2.0, я обнаружил, что низкоуровневые реализации
Math.Pow()
все еще в значительной степени точны для более поздних версий CLR.Таблица поиска находится в файле clr / src / vm / ecall.cpp. Раздел, который имеет отношение к
Math.Pow()
выглядит следующим образом:Поиск «COMDouble» приведет вас к clr / src / classlibnative / float / comfloat.cpp. Я избавлю вас от кода, просто посмотрите сами. Он в основном проверяет угловые случаи, затем вызывает версию CRT
pow()
.Единственная интересная деталь реализации - это макрос FCIntrinsic в таблице. Это намек на то, что джиттер может реализовать функцию как встроенную. Другими словами, замените вызов функции инструкцией машинного кода с плавающей запятой. Что не так, для
Pow()
него нет инструкции FPU. Но, конечно, для других простых операций. Следует отметить, что это может сделать математику с плавающей точкой в C # существенно быстрее, чем тот же код в C ++, проверьте этот ответ для причины.Кстати, исходный код для CRT также доступен, если у вас есть полная версия каталога Visual Studio vc / crt / src. Однако, вы не
pow()
ошибетесь, Microsoft купила этот код у Intel. Делать лучше, чем инженеры Intel, вряд ли. Хотя моя книга о старшей школе была в два раза быстрее, когда я попробовал:Но не является истинной заменой, потому что он накапливает ошибку от 3 операций с плавающей запятой и не решает проблемы домена, которые есть у Pow (). Как 0 ^ 0 и бесконечность, возведенная в любую степень.
источник
pow
общеизвестно, что трудно осуществить точно, будучи трансцендентной функцией (см . Дилемма Table-Maker ). Это намного проще с интегральной силой.Ответ Ханса Пассанта великолепен, но я хотел бы добавить, что если
b
целое число, то оноa^b
может быть очень эффективно вычислено с помощью двоичной декомпозиции. Вот измененная версия от Восторга Хакера Генри Уоррена :Он отмечает, что эта операция является оптимальной (выполняет минимальное количество арифметических или логических операций) для всех b <15. Также нет известного решения общей проблемы нахождения оптимальной последовательности факторов для вычисления
a^b
для любого b, кроме обширного поиск. Это проблема NP-Hard. Таким образом, в основном это означает, что двоичная декомпозиция настолько хороша, насколько это возможно.источник
a
это число с плавающей запятой.a
целое число, а код -. Как следствие этого, меня интересует точность результата "очень эффективного" вычисления текста.Если свободно доступная версия C
pow
является какой-либо индикацией, она не выглядит так, как вы ожидаете. Вам не очень поможет найти версию .NET, потому что проблема, которую вы решаете (то есть, с целыми числами), на несколько порядков проще и может быть решена в несколько строк кода на C # с возведением в степень по алгоритму возведения в квадрат .источник