С# Реализация 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;
}

Очень грубый метод, но если бы я использовал что-то более сложное, например метод журнала, вы могли бы спросить "и как я могу реализовать метод журнала?"