Skip to content

Instantly share code, notes, and snippets.

@NHDaly
Created November 5, 2018 15:53
Show Gist options
  • Save NHDaly/a8fae0d1d65ab1066c585c27e54146fa to your computer and use it in GitHub Desktop.
Save NHDaly/a8fae0d1d65ab1066c585c27e54146fa to your computer and use it in GitHub Desktop.
Benchmark Comparisons of representing numbers as Ints, Floats, and FixedDecimals of various bit sizes.
# Representation Comparisons
#
# This benchmark compares the performance of several numeric representations, over various
# numeric operations (+,-,*,/,÷...) on large arrays of numbers, in order to guide
# decision-making about how to represent fixed-decimal numbers.
#
# It compares fixed-decimal types against the builtin Int and Float types of various sizes.
# The output is written to a .csv file in the same directory as this file.
module DecimalBenchmarkComparisons
using FixedPointDecimals
using Random
using BenchmarkTools
using DataFrames
using CSV
# Create the array of data for the benchmark operaitions.
# Characteristics of the data:
# - Very many entries: N
# - Decimal values (with set precision): decimal_precision
# - Clustered tightly around 0 (to prevent overflow): -5:2, 2:5
# - None of the values _are_ 0 (to prevent divide by 0)
N = 1_000_000
decimal_precision = 2
float_incr = 1/(10^decimal_precision)
raw_data = Random.shuffle(vcat(rand.([-5:float_incr:-2, 2:float_incr:5], N)...))
# Express that data through the various types. Round it for integers.
fd_FixedPointDecimal_types = [
FixedPointDecimals.FixedDecimal{Int32, decimal_precision},
FixedPointDecimals.FixedDecimal{Int64, decimal_precision},
FixedPointDecimals.FixedDecimal{Int128, decimal_precision},
]
inttypes = [Int32,Int64,Int128]
floattypes = [Float32,Float64]
# Category for the results output CSV
category(::Type{<:Integer}) = "Int"
category(::Type{<:Union{Float32, Float64}}) = "Float"
category(::Type{<:FixedPointDecimals.FixedDecimal}) = "FixedDecimal"
# Collect the results
results = DataFrame(Operation=Symbol[], Category=String[], Type=DataType[],
MinDurationMs=Float64[], Allocations=Int[], MinGcTime=Number[],
Value=Number[])
# Run the benchmarks
for op in (:identity, :+, :*, :/, :÷)
println("$op")
for T in (inttypes..., floattypes..., fd_FixedPointDecimal_types...)
# Construct the data for the benchmark
print("$T ")
if T ∈ inttypes
data = T.(round.(raw_data))
else
data = T.(raw_data)
end
println("([$(join(data[1:3], ", "))...])") # preview data
# Create the function for the benchmark to call
f = op == :identity ? eval(op) : @eval (x)->$op($(T(10)),x)
# Run the benchmark
outs = fill(f(data[1]), length(data))
b = @benchmark for i in $(1:length(data)); $outs[i] = $f($data[i]); end
println(b)
value = sum(outs)
println(value)
push!(results, Dict(:Operation=>op, :Category=>category(T), :Type=>T,
:MinDurationMs=>b.times[1]/1_000_000, # ns->ms
:Allocations=>b.allocs[1], :MinGcTime=>b.gctimes[1],
:Value=>value))
end
end
println(results)
CSV.write("$(@__DIR__)/comparisons-benchmark-results.csv", results)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment