Skip to content

Instantly share code, notes, and snippets.

@asterite
Last active January 16, 2017 13:22
Show Gist options
  • Save asterite/7eba3e4af44bd3edc9bc61b8118f2e1f to your computer and use it in GitHub Desktop.
Save asterite/7eba3e4af44bd3edc9bc61b8118f2e1f to your computer and use it in GitHub Desktop.
require "big_int"
require "benchmark"
lib LibGMP
fun sizeinbase = __gmpz_sizeinbase(op : MPZ*, base : Int32) : Int32
fun export = __gmpz_export(rop : Void*, countp : Int32*, order : Int32, size : Int32, endian : Int32, nails : Int32, op : MPZ*) : UInt8*
end
struct BigInt
def size
LibGMP.sizeinbase(self, 256)
end
def bytes(format : IO::ByteFormat = IO::ByteFormat::SystemEndian) : Slice(UInt8)
e = format == IO::ByteFormat::BigEndian ? 1 : -1
Slice(UInt8).new(size).tap { |s| LibGMP.export s, nil, e, 1, 1, 0, self }
end
end
def to_hex_bytes_original(hex_str)
bytes = Bytes.new(hex_str.size / 2)
(0..hex_str.size - 2).step(2).with_index do |pos, i|
bytes[i] = hex_str[pos, 2].to_i(16).to_u8
end
bytes
end
def to_hex_bytes(string)
Bytes.new(string.bytesize / 2) do |i|
((string.to_slice[i*2].chr.to_i(16)) * 16 +
string.to_slice[i*2 + 1].chr.to_i(16)).to_u8
end
end
def from_base_16(value)
if '0' <= value <= '9'
(value - '0').to_u8
elsif 'A' <= value <= 'F'
10_u8 + (value - 'A')
elsif 'a' <= value <= 'f'
10_u8 + (value - 'a')
else
raise "Not an hex digit!"
end
end
def to_hex_bytes_improved(string)
Bytes.new(string.bytesize / 2) do |i|
from_base_16(string.to_slice[i*2].chr)*16 +
from_base_16(string.to_slice[i*2 + 1].chr)
end
end
def to_hex_bytes_big_int(string)
BigInt.new(string, 16).bytes(IO::ByteFormat::BigEndian)
end
string = "1F877C" * 100
bytes1 = to_hex_bytes_original(string)
bytes2 = to_hex_bytes(string)
bytes3 = to_hex_bytes_big_int(string)
bytes4 = to_hex_bytes_improved(string)
unless bytes1 == bytes2 == bytes3 == bytes4
abort "Bug in one implementation"
end
Benchmark.ips do |x|
x.report("original") do
to_hex_bytes_original(string)
end
x.report("big_int") do
to_hex_bytes_big_int(string)
end
x.report("normal") do
to_hex_bytes(string)
end
x.report("improved") do
to_hex_bytes_improved(string)
end
end
original 46.3k ( 21.6µs) (± 2.24%) 21.10× slower
big_int 249.98k ( 4.0µs) (± 2.33%) 3.91× slower
normal 363.38k ( 2.75µs) (± 2.73%) 2.69× slower
improved 976.77k ( 1.02µs) (± 2.46%) fastest
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment