How is Math.Pow() implemented in .NET Framework?
MethodImplOptions.InternalCall
That means that the method is actually implemented in the CLR, written in C++. The just-in-time compiler consults a table with internally implemented methods and compiles the call to the C++ function directly.
Having a look at the code requires the source code for the CLR. You can get that from the SSCLI20 distribution. It was written around the .NET 2.0 time frame, I've found the low-level implementations, like Math.Pow()
to be still largely accurate for later versions of the CLR.
The lookup table is located in clr/src/vm/ecall.cpp. The section that's relevant to Math.Pow()
looks like this:
FCFuncStart(gMathFuncs)
FCIntrinsic("Sin", COMDouble::Sin, CORINFO_INTRINSIC_Sin)
FCIntrinsic("Cos", COMDouble::Cos, CORINFO_INTRINSIC_Cos)
FCIntrinsic("Sqrt", COMDouble::Sqrt, CORINFO_INTRINSIC_Sqrt)
FCIntrinsic("Round", COMDouble::Round, CORINFO_INTRINSIC_Round)
FCIntrinsicSig("Abs", &gsig_SM_Flt_RetFlt, COMDouble::AbsFlt, CORINFO_INTRINSIC_Abs)
FCIntrinsicSig("Abs", &gsig_SM_Dbl_RetDbl, COMDouble::AbsDbl, CORINFO_INTRINSIC_Abs)
FCFuncElement("Exp", COMDouble::Exp)
FCFuncElement("Pow", COMDouble::Pow)
// etc..
FCFuncEnd()
Searching for "COMDouble" takes you to clr/src/classlibnative/float/comfloat.cpp. I'll spare you the code, just have a look for yourself. It basically checks for corner cases, then calls the CRT's version of pow()
.
The only other implementation detail that's interesting is the FCIntrinsic macro in the table. That's a hint that the jitter may implement the function as an intrinsic. In other words, substitute the function call with a floating point machine code instruction. Which is not the case for Pow()
, there is no FPU instruction for it. But certainly for the other simple operations. Notable is that this can make floating point math in C# substantially faster than the same code in C++, check this answer for the reason why.
By the way, the source code for the CRT is also available if you have the full version of Visual Studio vc/crt/src directory. You'll hit the wall on pow()
though, Microsoft purchased that code from Intel. Doing a better job than the Intel engineers is unlikely. Although my high-school book's identity was twice as fast when I tried it:
public static double FasterPow(double x, double y) {
return Math.Exp(y * Math.Log(x));
}
But not a true substitute because it accumulates error from 3 floating point operations and doesn't deal with the weirdo domain problems that Pow() has. Like 0^0 and -Infinity raised to any power.
How Math.Pow (and so on) actually works
pow is usually evaluated by this formula:
x^y = exp2(y*log2(x))
Functions exp2(x),log2(x)
are directly implemented in FPU. If you want to implement bignums then they can also be evaluated by basic operators with use of precomputed table of sqrt-powers like:
2^1/2, 2^1/4, 2^1/8, 2^1/16, 2^1/32 ...
to speed up the process
In case you need to handle also rooting for negative bases see this:
- real domain
pow
based on complex domain math
How wrong do I use Math.Pow(a,b) function in this C# code?
The power function for floating point numbers is only defined for positive base or integral exponent. Try
double c = - Math.Pow(8d, 1d / 3d);
Actually, 1/3 can't be represented exactly as a floating point number, but needs to be rounded. An exact real result for the rounded exponent does not even exist in theory.
Using the Math.Pow function
As far as the error you're getting:
Math.Pow takes 2 doubles as arguments and returns a double. Your method is declared as returning an int. This means that result is an int. You need to cast the result of Math.Pow to int:
result = (int)Math.Pow(firstNumber, secondNumber);
Are there any built-in .NET alternatives for using power of a number (Math.Pow) without errors?
The BigInteger
structure has a Pow
method. This structure resides in the System.Numerics
namespace, and was introduced in .NET Framework 4.0. You need to add a reference to the System.Numerics
assembly before using it.
using System;
using System.Numerics;
public static class Program
{
public static void Main(string[] args)
{
Console.WriteLine(BigInteger.Pow(17, 13)); // 9904578032905937
}
}
Note that BigInteger
is only suitable for integer arithmetic; it cannot handle fractional numbers.
C# Math.Pow() is broken
Seems to be exactly as specified; from the Math.Pow() remarks section on Pow(x,y)
;
Parameters
x < 0 but not NegativeInfinity; y is not an integer, NegativeInfinity, or PositiveInfinity.Result
NaN
Related Topics
Windows Like Services Development in Linux Using Mono
Casting Interfaces for Deserialization in JSON.Net
Distinct by Property of Class with Linq
How to Change Network Settings (Ip Address, Dns, Wins, Host Name) with Code in C#
Up, Down, Left and Right Arrow Keys Do Not Trigger Keydown Event
How to Get Dropdownlist Selectedvalue in Controller in MVC
Copy File(S) from One Project to Another Using Post Build Event...Vs2010
Copying from and to Clipboard Loses Image Transparency
How to Make Sure That String Is Valid JSON Using JSON.Net
Can You Develop Linux Applications with Xamarin
Generics in C#, Using Type of a Variable as Parameter
How to Add System.Windows.Interactivity to Project
How to Elevate Privileges Only When Required