Created
August 24, 2011 18:25
-
-
Save markusl/1168776 to your computer and use it in GitHub Desktop.
Implementing the Fast inverse square root (InvSqrt) in F#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#load "FsharpChart.fsx" | |
open MSDN.FSharp.Charting | |
let castValue (value : 'TSource) :'TResult = | |
let an = new System.Reflection.AssemblyName("CastUtil") | |
let ab = System.AppDomain.CurrentDomain.DefineDynamicAssembly(an, System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave) | |
let mb = ab.DefineDynamicModule(an.Name) | |
let tb = mb.DefineType("CastUtil", System.Reflection.TypeAttributes.Public ||| System.Reflection.TypeAttributes.Class) | |
let fb = tb.DefineMethod("Read", System.Reflection.MethodAttributes.Public ||| System.Reflection.MethodAttributes.Static, typeof<'TResult>, ([|typeof<'TSource>|])) | |
let ig = fb.GetILGenerator() | |
ig.Emit(System.Reflection.Emit.OpCodes.Ldarg_0) | |
let local = ig.DeclareLocal(typeof<'TSource>) | |
ig.Emit(System.Reflection.Emit.OpCodes.Stloc, local) | |
ig.Emit(System.Reflection.Emit.OpCodes.Ldloca_S, local) | |
ig.Emit(System.Reflection.Emit.OpCodes.Ldobj, typeof<'TResult>) | |
ig.Emit(System.Reflection.Emit.OpCodes.Ret) | |
let cl = tb.CreateType() | |
let readMethod = cl.GetMethod("Read", System.Reflection.BindingFlags.Static ||| System.Reflection.BindingFlags.Public) | |
readMethod.Invoke(null, [|value|]) :?> 'TResult | |
let readPtr1 (value : nativeptr<'TSource>) :'TResult = (# "ldobj !0" type ('TResult) value : 'TResult #) | |
let invsqrt_1 xx = | |
let halfx = 0.5F * xx | |
let mutable x = xx | |
let mutable i = (0x5f3759df) - ((readPtr1 &&x) >>> 1) | |
x <- readPtr1 &&i | |
x * (1.5F - halfx*x*x) | |
let invsqrt_2 xx = | |
let halfx = 0.5F * xx | |
let x:int = castValue xx | |
let mutable i = (0x5f3759df) - (x >>> 1) | |
let x:float32 = castValue i | |
x * (1.5F - halfx*x*x) | |
let z = 0.1 | |
let y:int = castValue z | |
let normal = 1./System.Math.Sqrt(0.01) | |
let fast = invsqrt_2 0.01F | |
printfn "%f %f" normal fast | |
let getValue x = | |
let fast = (invsqrt (x)) | |
let slow = (1./(System.Math.Sqrt((float)x))) | |
fast - (float32)slow | |
[for x in 0.01 .. 0.001 ..10. -> getValue ((float32)x)] |> FSharpChart.Line | |
// See http://jheriko-rtw.blogspot.com/2009/04/understanding-and-improving-fast.html | |
// for original algorithm |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Keep in mind that this is just a WIP version of proof-of-concept of how to implement/use "pointers" in F#. :-)