Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
rustflags = ["-A", "long_running_const_eval"]
41 changes: 28 additions & 13 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Rust CI (nightly + benches)
on:
push:
branches: ["**"]

pull_request:
branches: [master]
types: [opened, reopened, synchronize, edited]
Expand Down Expand Up @@ -33,42 +32,58 @@ jobs:
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-registry-
restore-keys: |
${{ runner.os }}-cargo-registry-
- uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-target-nightly-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-target-nightly-
restore-keys: |
${{ runner.os }}-target-nightly-
- run: cargo build --workspace --all-features --verbose
- run: cargo test --workspace --all-features --verbose
- run: cargo test --workspace --all-features --verbose

bench:
name: Benchmarks (PR → master)
name: Benches (PR → master)
if: github.event_name == 'pull_request' && github.base_ref == 'master'
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write

steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
override: true

- uses: bencherdev/bencher@main

- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-registry-

- name: Run Criterion benches and push to Bencher
restore-keys: |
${{ runner.os }}-cargo-registry-
- uses: bencherdev/bencher@main
- run: sudo apt-get update && sudo apt-get install -y valgrind
- run: |
version=$(awk -F\" '/iai-callgrind =/ {print $2; exit}' benchmark_iai_callgrind/Cargo.toml)
cargo install iai-callgrind-runner --version "$version"
- name: Push IAI-Callgrind results to Bencher
env:
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
run: |
BRANCH="${{ github.head_ref }}"
bencher run \
--adapter rust_iai_callgrind \
--branch "$BRANCH" \
--testbed ci-github-ubuntu-latest \
--project "extended-float" \
--github-actions "${{ secrets.GITHUB_TOKEN }}" \
--err \
"cargo bench --manifest-path benchmark_iai_callgrind/Cargo.toml"
- name: Push Criterion benches to Bencher
env:
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
run: |
Expand All @@ -80,4 +95,4 @@ jobs:
--project "extended-float" \
--github-actions "${{ secrets.GITHUB_TOKEN }}" \
--err \
"cargo bench"
"cargo bench --manifest-path benchmark/Cargo.toml"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/target
target/
**/*.rs.bk
.vscode
.rrun_ignore
Expand Down
26 changes: 14 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@ edition = "2024"
authors = ["Ivan Gureev"]
description = "Extended floating-point number implementation for Rust"
license = "MIT"
homepage = "https://github.com/varche1/extended_float"
repository = "https://github.com/varche1/extended_float"
keywords = ["float", "math", "numerical", "decimal", "IEEE 754"]
readme = "README.md"
keywords = ["float", "math", "numerical", "numeric", "decimal", "IEEE 754", "fixed-point",]
categories = ["science", "mathematics"]
autobenches = false
exclude = ["examples/*", "benchmark/*"]

[lib]
bench = false

[dependencies]
num-traits = "0.2"
ryu = "1"
dtoa = "1"
fast-float = "0.2"

# TODO: remove unnecessary
[dev-dependencies]
pretty_assertions = "1"
criterion = "0.5"
fastnum = "0.2"
rust_decimal = "1.37"
pretty_assertions = "^1"
rand = "^0.9"

[[bench]]
name = "bench_ops"
harness = false
path = "benches/bench_ops.rs"
[profile.release]
lto = true # enable link-time optimisation for faster runtime, but slower compile time
opt-level = 3 # maximum optimisation level for faster runtime, but slower compile time
24 changes: 0 additions & 24 deletions Makefile

This file was deleted.

37 changes: 37 additions & 0 deletions benchmark/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[package]
name = "extended_float_benchmarks"
version = "0.1.0"
edition = "2024"
authors = ["Ivan Gureev"]
license = "MIT"

[dev-dependencies]
criterion = { version = "^0.5" }
extended_float = { path = "../" }
fastnum = "^0.2"
rust_decimal = "^1.37"
bigdecimal = "^0.4.6"
decimal-rs = "^0.1.43"
rand = "^0.9"

[[bench]]
name = "ops"
path = "benches/ops.rs"
harness = false

[[bench]]
name = "conversions"
path = "benches/conversions.rs"
harness = false

[[test]]
name = "bench_utils_test"
path = "benches/common/random.rs"

[features]
default = []
comparison = []

[profile.release]
lto = true # enable link-time optimisation for faster runtime, but slower compile time
opt-level = 3 # maximum optimisation level for faster runtime, but slower compile time
7 changes: 7 additions & 0 deletions benchmark/benches/common/criterion_conf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use criterion::Criterion;

pub fn configure_criterion() -> Criterion {
Criterion::default()
.warm_up_time(std::time::Duration::from_millis(1000))
.measurement_time(std::time::Duration::from_millis(2000))
}
30 changes: 30 additions & 0 deletions benchmark/benches/common/files.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;

pub fn read_lines_from_file<P>(filename: P) -> io::Result<Vec<Vec<u8>>>
where
P: AsRef<Path>,
{
let file = File::open(filename)?;
let buf_reader = io::BufReader::new(file);
let mut data = Vec::new();

for line in buf_reader.lines() {
let line = line?;
data.push(line.into_bytes());
}

Ok(data)
}

pub fn read_file_as_strings<P>(filename: P) -> io::Result<Vec<String>>
where
P: AsRef<Path>,
{
let file_data = read_lines_from_file(filename)?;
Ok(file_data
.iter()
.map(|bytes| String::from_utf8(bytes.clone()).expect("invalid UTF-8"))
.collect())
}
3 changes: 3 additions & 0 deletions benchmark/benches/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod files;
pub mod random;
pub mod criterion_conf;
97 changes: 97 additions & 0 deletions benchmark/benches/common/random.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use std::ops::RangeInclusive;

use rand::prelude::*;

pub struct RandomF64Iterator {
factor: f64,
start: f64,
end: f64,
rng: StdRng,
}

impl RandomF64Iterator {
pub fn new(seed: u64, precision: usize, range: RangeInclusive<f64>) -> Self {
RandomF64Iterator {
factor: 10_f64.powi(precision as i32),
start: *range.start(),
end: *range.end(),
rng: StdRng::seed_from_u64(seed),
}
}
}

impl Iterator for RandomF64Iterator {
type Item = f64;

fn next(&mut self) -> Option<Self::Item> {
let value = self.rng.random_range(self.start..=self.end);
Some((value * self.factor).round() / self.factor)
}
}

pub struct RandomF64StringIterator {
inner: RandomF64Iterator,
}

impl RandomF64StringIterator {
pub fn new(seed: u64, precision: usize, range: RangeInclusive<f64>) -> Self {
RandomF64StringIterator {
inner: RandomF64Iterator::new(seed, precision, range),
}
}
}

impl Iterator for RandomF64StringIterator {
type Item = String;

fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|f| format!("{}", f))
}
}

#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::*;

#[test]
fn test_random_f64_iterator() {
let mut iterator = RandomF64Iterator::new(12345, 3, -100000.0..=100000.0);
assert_eq!(iterator.next(), Some(-38813.542));
assert_eq!(iterator.next(), Some(76623.125));
assert_eq!(iterator.next(), Some(9318.383));

let mut iterator = RandomF64Iterator::new(12345, 5, -100000.0..=100000.0);
assert_eq!(iterator.next(), Some(-38813.54153));
assert_eq!(iterator.next(), Some(76623.12532));
assert_eq!(iterator.next(), Some(9318.38349));
}

#[test]
fn test_random_f64_iterator_as_str() {
let mut iterator =
RandomF64Iterator::new(12345, 3, -100000.0..=100000.0).map(|f| format!("{}", f));
assert_eq!(iterator.next(), Some("-38813.542".to_string()));
assert_eq!(iterator.next(), Some("76623.125".to_string()));
assert_eq!(iterator.next(), Some("9318.383".to_string()));

let mut iterator =
RandomF64Iterator::new(12345, 5, -100000.0..=100000.0).map(|f| format!("{}", f));
assert_eq!(iterator.next(), Some("-38813.54153".to_string()));
assert_eq!(iterator.next(), Some("76623.12532".to_string()));
assert_eq!(iterator.next(), Some("9318.38349".to_string()));
}

#[test]
fn test_random_f64_string_iterator() {
let mut iterator = RandomF64StringIterator::new(12345, 3, -100000.0..=100000.0);
assert_eq!(iterator.next(), Some("-38813.542".to_string()));
assert_eq!(iterator.next(), Some("76623.125".to_string()));
assert_eq!(iterator.next(), Some("9318.383".to_string()));

let mut iterator = RandomF64StringIterator::new(12345, 5, -100000.0..=100000.0);
assert_eq!(iterator.next(), Some("-38813.54153".to_string()));
assert_eq!(iterator.next(), Some("76623.12532".to_string()));
assert_eq!(iterator.next(), Some("9318.38349".to_string()));
}
}
Loading
Loading