Last active
October 31, 2023 15:34
-
-
Save r1pper/b8f4620a8f7718b16df9 to your computer and use it in GitHub Desktop.
Fast float Logarithm in C# using lookup Table
This file contains hidden or 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
using System; | |
using System.Runtime.InteropServices; | |
namespace Test2 | |
{ | |
public static class FastLog | |
{ | |
[StructLayout(LayoutKind.Explicit)] | |
private struct Ieee754 | |
{ | |
[FieldOffset(0)] public float Single; | |
[FieldOffset(0)] public uint UnsignedBits; | |
[FieldOffset(0)] public int SignedBits; | |
public uint Sign | |
{ | |
get | |
{ | |
return UnsignedBits >> 31; | |
} | |
} | |
public int Exponent | |
{ | |
get | |
{ | |
return (SignedBits >> 23) & 0xFF; | |
} | |
} | |
public uint Mantissa | |
{ | |
get | |
{ | |
return UnsignedBits & 0x007FFFFF; | |
} | |
} | |
} | |
private static readonly float[] MantissaLogs = new float[(int) Math.Pow(2, 23)]; | |
private const float Base10 = 3.321928F; | |
private const float BaseE = 1.442695F; | |
static FastLog() | |
{ | |
//creating lookup table | |
for (uint i = 0; i < MantissaLogs.Length; i++) | |
{ | |
var n = new Ieee754 {UnsignedBits = i | 0x3F800000}; //added the implicit 1 leading bit | |
MantissaLogs[i] = (float) Math.Log(n.Single, 2); | |
} | |
} | |
public static float Log2(float value) | |
{ | |
if (value == 0F) | |
return float.NegativeInfinity; | |
var number = new Ieee754 {Single = value}; | |
if (number.UnsignedBits >> 31 == 1) //NOTE: didn't call Sign property for higher performance | |
return float.NaN; | |
return (((number.SignedBits >> 23) & 0xFF) - 127) + MantissaLogs[number.UnsignedBits & 0x007FFFFF]; | |
//NOTE: didn't call Exponent and Mantissa properties for higher performance | |
} | |
public static float Log10(float value) | |
{ | |
return Log2(value)/Base10; | |
} | |
public static float Ln(float value) | |
{ | |
return Log2(value)/BaseE; | |
} | |
public static float Log(float value, float valueBase) | |
{ | |
return Log2(value)/Log2(valueBase); | |
} | |
} | |
} |
This file contains hidden or 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
using System; | |
using System.Collections.Generic; | |
using System.Data; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using Microsoft.Win32; | |
namespace Test2 | |
{ | |
class Program | |
{ | |
private static void Main(string[] args) | |
{ | |
var watch = new Stopwatch(); | |
FastLog.Log2(1); //create table for the fist time | |
Console.WriteLine("benchmarking .net log10..."); | |
var doubleValue = 1.0; | |
watch.Reset(); | |
watch.Start(); | |
for (var i = 0; i < 1000000000; i++) | |
{ | |
Math.Log10(doubleValue); | |
doubleValue+=1.0; | |
} | |
watch.Stop(); | |
var netTime = watch.Elapsed; | |
Console.WriteLine("result: {0}", netTime); | |
Console.WriteLine("benchmarking fast log10..."); | |
var floatValue = 1.0F; | |
watch.Reset(); | |
watch.Start(); | |
for (var i = 0; i < 1000000000; i++) | |
{ | |
FastLog.Log10(floatValue); | |
floatValue += 1.0F; | |
} | |
watch.Stop(); | |
var fastTime = watch.Elapsed; | |
Console.WriteLine("result: {0}", fastTime); | |
Console.WriteLine("ratio: {0}", netTime.TotalMilliseconds / (float)fastTime.TotalMilliseconds); | |
Console.WriteLine("done."); | |
Console.ReadKey(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment