Skip to content

Commit

Permalink
test: add benchmark comparing against fpdec crate (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
MathisWellmann authored Oct 25, 2024
1 parent 788f145 commit cd8c1d3
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to `const-decimal`.

## Unreleased

- Add `fpdec_comparison` benchmark.
- Parse strings without a decimal point.
- Add `quantize_round_to_zero`.
- Impl `num_traits::Zero`, `num_traits::One`, and `std::ops::Rem`.

## 0.3.0

- BREAKING: Remove `from_scaled` in favor of `try_from_scaled`.
Expand Down
27 changes: 27 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ thiserror = "1.0.63"
[dev-dependencies]
criterion = "0.5.1"
expect-test = "1.5.0"
fpdec = "0.11.0"
malachite = "0.4.16"
proptest = "1.5.0"

Expand All @@ -59,3 +60,8 @@ incremental = false
name = "main"
path = "benches/main.rs"
harness = false

[[bench]]
name = "fpdec_comparison"
path = "benches/fpdec_comparison.rs"
harness = false
155 changes: 155 additions & 0 deletions benches/fpdec_comparison.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//! Compare `const-decimal` with [`fpdec.rs`](https://github.com/mamrhein/fpdec.rs)

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use fpdec::{Dec, Decimal};

// Lots of black boxes, maybe overkill.
fn criterion_benchmark(c: &mut Criterion) {
// Create instances here to avoid benchmarking the constructor.
let fpdec_0 = fpdec::Decimal::new_raw(100, 0);
let fpdec_1 = fpdec::Decimal::new_raw(110, 0);

let const_decimal_i32_0 = const_decimal::Decimal::<i32, 4>::try_from_scaled(100, 0).unwrap();
let const_decimal_i32_1 = const_decimal::Decimal::<i32, 4>::try_from_scaled(110, 0).unwrap();

let const_decimal_i64_0 = const_decimal::Decimal::<i64, 4>::try_from_scaled(100, 0).unwrap();
let const_decimal_i64_1 = const_decimal::Decimal::<i64, 4>::try_from_scaled(110, 0).unwrap();

c.bench_function(&format!("fpdec_add"), |b| {
b.iter(|| {
let _ = black_box(black_box(fpdec_0) + black_box(fpdec_1));
})
});
c.bench_function(&format!("const_decimal_i32_add"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i32_0) + black_box(const_decimal_i32_1));
})
});
c.bench_function(&format!("const_decimal_i64_add"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i64_0) + black_box(const_decimal_i64_1));
})
});

c.bench_function(&format!("fpdec_sub"), |b| {
b.iter(|| {
let _ = black_box(black_box(fpdec_0) - black_box(fpdec_1));
})
});
c.bench_function(&format!("const_decimal_i32_sub"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i32_0) - black_box(const_decimal_i32_1));
})
});
c.bench_function(&format!("const_decimal_i64_sub"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i64_0) - black_box(const_decimal_i64_1));
})
});

c.bench_function(&format!("fpdec_mul"), |b| {
b.iter(|| {
let _ = black_box(black_box(fpdec_0) * black_box(fpdec_1));
})
});
c.bench_function(&format!("const_decimal_i32_mul"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i32_0) * black_box(const_decimal_i32_1));
})
});
c.bench_function(&format!("const_decimal_i64_mul"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i64_0) * black_box(const_decimal_i64_1));
})
});

c.bench_function(&format!("fpdec_div"), |b| {
b.iter(|| {
let _ = black_box(black_box(fpdec_0) / black_box(fpdec_1));
})
});
c.bench_function(&format!("const_decimal_i32_div"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i32_0) / black_box(const_decimal_i32_1));
})
});
c.bench_function(&format!("const_decimal_i64_div"), |b| {
b.iter(|| {
black_box(black_box(const_decimal_i64_0) / black_box(const_decimal_i64_1));
})
});

// Some real-world use case examples. Linear futures profit and loss
// calculations. Quantity denoted in BaseCurrency.
let fpdec_entry_price = Dec!(100);
let fpdec_exit_price = Dec!(110);
let fpdec_qty = Dec!(5);

let const_decimal_i32_entry_price =
const_decimal::Decimal::<i32, 2>::try_from_scaled(100, 0).unwrap();
let const_decimal_i32_exit_price =
const_decimal::Decimal::<i32, 2>::try_from_scaled(110, 0).unwrap();
let const_decimal_i32_qty = const_decimal::Decimal::<i32, 2>::try_from_scaled(5, 0).unwrap();

let const_decimal_i64_entry_price =
const_decimal::Decimal::<i64, 2>::try_from_scaled(100, 0).unwrap();
let const_decimal_i64_exit_price =
const_decimal::Decimal::<i64, 2>::try_from_scaled(110, 0).unwrap();
let const_decimal_i64_qty = const_decimal::Decimal::<i64, 2>::try_from_scaled(5, 0).unwrap();

c.bench_function(&format!("fpdec_linear_futures_pnl"), |b| {
b.iter(|| {
let _ = black_box(fpdec_exit_price * fpdec_qty - fpdec_entry_price * fpdec_qty);
})
});
c.bench_function(&format!("const_decimal_i32_linear_futures_pnl"), |b| {
b.iter(|| {
black_box(
const_decimal_i32_exit_price * const_decimal_i32_qty
- const_decimal_i32_entry_price * const_decimal_i32_qty,
);
})
});
c.bench_function(&format!("const_decimal_i64_linear_futures_pnl"), |b| {
b.iter(|| {
black_box(
const_decimal_i64_exit_price * const_decimal_i64_qty
- const_decimal_i64_entry_price * const_decimal_i64_qty,
);
})
});

// Inverse futures profit and loss calculation. Quantity is denoted in
// QuoteCurrency.
let fpdec_qty = Dec!(500);
let const_decimal_i32_qty = const_decimal::Decimal::<i32, 2>::try_from_scaled(500, 0).unwrap();
let const_decimal_i64_qty = const_decimal::Decimal::<i64, 2>::try_from_scaled(500, 0).unwrap();

c.bench_function(&format!("fpdec_inverse_futures_pnl"), |b| {
b.iter(|| {
let _ = black_box(
black_box(fpdec_qty) / black_box(fpdec_entry_price)
- black_box(fpdec_qty) / black_box(fpdec_exit_price),
);
})
});
c.bench_function(&format!("const_decimal_i32_inverse_futures_pnl"), |b| {
b.iter(|| {
black_box(
black_box(const_decimal_i32_qty) / black_box(const_decimal_i32_entry_price)
- black_box(const_decimal_i32_qty) / black_box(const_decimal_i32_exit_price),
);
})
});
c.bench_function(&format!("const_decimal_i64_inverse_futures_pnl"), |b| {
b.iter(|| {
black_box(
black_box(const_decimal_i64_qty) / black_box(const_decimal_i64_entry_price)
- black_box(const_decimal_i64_qty) / black_box(const_decimal_i64_exit_price),
);
})
});
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

0 comments on commit cd8c1d3

Please sign in to comment.