Skip to content

Instantly share code, notes, and snippets.

@timotheecour
Last active December 1, 2020 08:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timotheecour/a9bbd9cf19b99b1e3ae8f639f9647ccd to your computer and use it in GitHub Desktop.
Save timotheecour/a9bbd9cf19b99b1e3ae8f639f9647ccd to your computer and use it in GitHub Desktop.
const digitsTable* = "0001020304050607080910111213141516171819" &
"2021222324252627282930313233343536373839" &
"4041424344454647484950515253545556575859" &
"6061626364656667686970717273747576777879" &
"8081828384858687888990919293949596979899"
func digits10*(num: uint64): int {.noinline.} =
if num < 10:
result = 1
elif num < 100:
result = 2
elif num < 1_000:
result = 3
elif num < 10_000:
result = 4
elif num < 100_000:
result = 5
elif num < 1_000_000:
result = 6
elif num < 10_000_000:
result = 7
elif num < 100_000_000:
result = 8
elif num < 1_000_000_000:
result = 9
elif num < 10_000_000_000'u64:
result = 10
elif num < 100_000_000_000'u64:
result = 11
elif num < 1_000_000_000_000'u64:
result = 12
else:
result = 12 + digits10(num div 1_000_000_000_000'u64)
template numToString*(result: var string, origin: uint64, length: int) =
var num = origin
var next = length - 1
while num >= 100:
let originNum = num
num = num div 100
let index = (originNum - num * 100) shl 1
result[next] = digitsTable[index + 1]
result[next - 1] = digitsTable[index]
dec(next, 2)
# process last 1-2 digits
if num < 10:
result[next] = chr(ord('0') + num)
else:
let index = num * 2
result[next] = digitsTable[index + 1]
result[next - 1] = digitsTable[index]
proc toString*(x: uint64): string {.noSideEffect, raises: [].} =
## The stringify operator for an unsigned integer argument. Returns `x`
## converted to a decimal string.
if x == 0:
return "0"
elif x == 1:
return "1"
let length = digits10(x)
setLen(result, length)
numToString(result, x, length)
when false:
import std/monotimes
template benchmark(name, fn): untyped =
proc name() =
block:
let past1 = getMonoTime()
for i in 1000 .. 8000:
discard fn(uint64(i))
let last1 = getMonoTime() - past1
echo astToStr(fn) & ": " & $last1
benchmark(hello1, `$`)
benchmark(hello2, tostring)
for i in 0 ..< 10:
hello2()
hello1()
import std/times
import std/random
proc main =
var list: seq[uint64]
let n = 10_000_000
for i in 0..<n:
# list.add rand(uint64.high) # TODO: support
# list.add cast[uint64](rand(int64.high)) # TODO: support
list.add cast[uint64](rand(int.high))
var s = ""
var x = 0
template fn(algo) =
let t = cpuTime()
for i in 0..<n:
s = algo(list[i])
x += cast[int](s[^1])
let t2 = cpuTime()
echo (astToStr(algo), x, t2 - t)
for i in 0..<4:
fn(`$`)
fn(tostring)
main()
#[
("`$`", 524991986, 0.54838)
("tostring", 1049983972, 0.414097)
("`$`", 1574975958, 0.5607880000000001)
("tostring", 2099967944, 0.4496660000000001)
("`$`", 2624959930, 0.5813800000000002)
("tostring", 3149951916, 0.4429910000000001)
("`$`", 3674943902, 0.5727789999999997)
("tostring", 4199935888, 0.4341140000000001)
]#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment