Created
August 17, 2024 00:41
-
-
Save voronoipotato/fa4834afa20f3b00d55b64e378080489 to your computer and use it in GitHub Desktop.
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
open BenchmarkDotNet.Attributes | |
open BenchmarkDotNet.Running | |
open BenchmarkDotNet.Jobs | |
open System | |
open Microsoft.FSharp.NativeInterop | |
type Chars () = | |
static member chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".AsSpan() | |
let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
let b36Unfold (number: int) = | |
let unfoldFunc n = | |
if n = 0 then None | |
else | |
let remainder = n % 36 | |
let quotient = n / 36 | |
Some (chars.[remainder], quotient) | |
Array.unfold unfoldFunc number | |
|> Array.rev | |
|> System.String | |
let b36Span (number:int) = | |
let digits = Math.Log(number, 36.0) |> ceil |> int | |
let mem = NativePtr.stackalloc<char>(digits) |> NativePtr.toVoidPtr | |
let nativeSpan = Span<char>(mem, digits) | |
let mutable (n:int) = number | |
for identifier = digits downto 1 do //identifier = 1 to digits do | |
nativeSpan[identifier-1] <- Chars.chars.[n%36] | |
n <- n/36 | |
nativeSpan.ToString() | |
let toBase36 n = | |
let mutable num = n | |
let mutable r = 0 | |
let mutable newNumber = "" | |
while num >= 36 do | |
r <- num % 36 | |
newNumber <- string (chars.[r]) + newNumber | |
num <- num / 36 | |
newNumber <- string (chars.[num]) + newNumber | |
newNumber | |
let toBase36Rec n = | |
let rec toBase36 n state = | |
if n < 36 then | |
string state | |
else | |
let r = n % 36 | |
let newState = chars[r] :: state | |
toBase36 (n/36) newState | |
toBase36 n List.empty | |
[<SimpleJob(RuntimeMoniker.Net80)>] | |
type Benchmarks() = | |
[<Params(123, 245685, 3000000)>] | |
member val size = 0 with get, set | |
[<Benchmark>] | |
member __.B36Unfold () = b36Unfold __.size | |
[<Benchmark>] | |
member __.B36Span () = b36Span __.size | |
[<Benchmark>] | |
member __.B36Mutable () = toBase36 __.size | |
[<Benchmark>] | |
member __.B36Rec () = toBase36Rec __.size | |
BenchmarkRunner.Run<Benchmarks>() |> ignore |
I would just make the function take an unsigned int personally. negative base36 is not valid for most consumers
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As a heads up, I needed to add support around some of the outputs
Math.Log
outputs. This function also is only working for positive integers so depending on the developer's needs, this is something to keep in mind for edge cases.