Last active
December 1, 2020 08:09
-
-
Save timotheecour/a9bbd9cf19b99b1e3ae8f639f9647ccd 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
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