С# Реализация Math.Sqrt
В последнее время я использую System.Math довольно много, и на днях мне было интересно, как Microsoft применила бы метод Sqrt в библиотеке. Поэтому я открыл свой лучший помощник рефлектора и попытался разобрать метод в библиотеке, но он показал:
[MethodImpl(MethodImplOptions.InternalCall),ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern double Sqrt(double d);
В тот день в первый раз я понял, насколько зависимы мои дети на каркасе, есть.
Анекдоты, но мне интересно, какой алгоритм MS использовал бы для реализации этого метода или другими словами, как бы вы написали свою собственную реализацию Math.Sqrt в С#, если у вас не было поддержки библиотеки.
Приветствия
Ответы
Ответ 1
Любой из методов, найденных с помощью Reflector или Reference Source, которые имеют атрибут MethodImplOptions.InternalCall, фактически реализуется на С++ внутри CLR. Вы можете получить исходный код для них из дистрибутива SSCLI20. Соответствующим файлом является clr/src/vm/ecall.cpp, он содержит таблицу имен методов с указателями функций, используемую компилятором JIT для непосредственного встраивания адреса вызова в сгенерированный машинный код. Соответствующий раздел таблицы
FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
...
Что переносит вас в clr/src/classlibnative/float/comfloat.cpp
FCIMPL1_V(double, COMDouble::Sqrt, double d)
WRAPPER_CONTRACT;
STATIC_CONTRACT_SO_TOLERANT;
return (double) sqrt(d);
FCIMPLEND
Он просто вызывает функцию CRT. Но это не то, что происходит в джиттере x86, обратите внимание на "внутреннюю" в объявлении таблицы. Вы не найдете этого в версии джиттера SSLI20, это простой, не обремененный патентами. Однако судоходство превращает его в внутреннее:
double d = 2.0;
Console.WriteLine(Math.Sqrt(d));
переводится на
00000008 fld dword ptr ds:[0072156Ch]
0000000e fsqrt
..etc
Другими словами, Math.Sqrt() преобразуется в одну командную инструкцию машинного кода с плавающей запятой. В разделе этот ответ подробно рассказывается о том, как это удобно использовать для собственного кода.
Ответ 2
Функция будет переведена в инструкции ассемблера. Например, команда fsqrt
для x87.
Вы можете использовать числа с плавающей запятой в программном обеспечении, но это, скорее всего, будет намного медленнее. Я думаю, для Sqrt итеративный алгоритм типичной реализации.
Ответ 3
Google.com предоставит вам больше ответов, чем StackOverflow.com
Посмотрите на эту страницу:
http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
Один алгоритм можно найти под заголовком "Двоичная цифровая система (база 2)" на указанной выше странице вики.
Но реализация программного обеспечения НЕ будет эффективной. Современный процессор имеет аппаратные реализации для математических функций в FPU. Вам просто нужно вызвать правильные инструкции процессора (на языке сборки или машины)
Ответ 4
public double Sqrt(int number)
{
double x = number / 2;
for (int i = 0; i < 100; i++) x = (x + number / x) / 2d;
return x;
}
Очень грубый метод, но если бы я использовал что-то более сложное, например метод журнала, вы могли бы спросить "и как я могу реализовать метод журнала?"