Skip to content
Merged
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
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
name: CI

on:
push:
pull_request:
[push, pull_request, workflow_dispatch]

jobs:
test:
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Lint

on:
[push, pull_request, workflow_dispatch]

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
components: rustfmt, clippy
- run: cargo check
- run: cargo fmt -- --check
- run: RUSTFLAGS="--deny warnings" cargo build
- run: cargo clippy --all-features -- --deny warnings
20 changes: 20 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
avoid-breaking-exported-api = false
disallowed-macros = [
# Can also use an inline table with a `path` key.
{ path = "std::print", reason = "no IO allowed" },
{ path = "std::println", reason = "no IO allowed" },
{ path = "std::format", reason = "no string allocation allowed" },
{ path = "std::debug", reason = "debugging macros should not be present in any release" },
# NOTE: unimplemented is fine because this can be for intentionally disabled methods
{ path = "std::todo", reason = "should never have TODO macros in releases" },
]
disallowed-methods = [
{ path = "std::io::stdout", reason = "no IO allowed" },
{ path = "std::io::stdin", reason = "no IO allowed" },
{ path = "std::io::stderr", reason = "no IO allowed" },
]
disallowed-types = [
{ path = "std::io::File", reason = "no IO allowed" },
{ path = "std::io::BufReader", reason = "need our own abstractions for reading/writing" },
{ path = "std::io::BufWriter", reason = "need our own abstractions for reading/writing" },
]
10 changes: 2 additions & 8 deletions extras/data-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ impl TestCase {
let (value, len) = r.unwrap();
if len != self.string.len() || value != expected {
if len != self.string.len() {
eprintln!(
"Expected empty string remainder, got: {:?}",
self.string.len() - len
);
eprintln!("Expected empty string remainder, got: {:?}", self.string.len() - len);
}
if value != expected {
eprintln!("Expected output {}, got {}", expected, value);
Expand All @@ -51,10 +48,7 @@ impl TestCase {

fn parse_test_file(filename: impl AsRef<Path>) -> impl Iterator<Item = TestCase> {
let file = File::open(filename).unwrap();
BufReader::new(file)
.lines()
.map(Result::unwrap)
.map(TestCase::parse)
BufReader::new(file).lines().map(Result::unwrap).map(TestCase::parse)
}

fn run_test_cases(filename: impl AsRef<Path>) -> usize {
Expand Down
67 changes: 28 additions & 39 deletions extras/simple-bench/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,14 @@ use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Instant;

use fast_float2::FastFloat;
use fastrand::Rng;
use lexical::FromLexical;
use structopt::StructOpt;

use fast_float2::FastFloat;

use random::RandomGen;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(
name = "fast-float-simple-bench",
about = "fast-float benchmark utility",
no_version
)]
#[structopt(name = "fast-float-simple-bench", about = "fast-float benchmark utility", no_version)]
struct Opt {
/// Parse numbers as float32 (default is float64)
#[structopt(short, long = "32")]
Expand Down Expand Up @@ -146,9 +140,7 @@ impl Method {
fast_float::parse_partial::<T, _>(s).unwrap_or_default().0
}),
Self::Lexical => run_bench(data, repeat, |s: &str| {
lexical_core::parse_partial::<T>(s.as_bytes())
.unwrap_or_default()
.0
lexical_core::parse_partial::<T>(s.as_bytes()).unwrap_or_default().0
}),
Self::FromStr => run_bench(data, repeat, |s: &str| s.parse::<T>().unwrap_or_default()),
};
Expand Down Expand Up @@ -180,12 +172,8 @@ fn print_report(results: &[BenchResult], title: &str) {
println!("| {:^width$} |", title, width = width);
println!("|{:=<width$}|", "", width = width + 2);
print_table("ns/float", results, width, |t, n, _| t as f64 / n as f64);
print_table("Mfloat/s", results, width, |t, n, _| {
1e3 * n as f64 / t as f64
});
print_table("MB/s", results, width, |t, _, b| {
b as f64 * 1e9 / 1024. / 1024. / t as f64
});
print_table("Mfloat/s", results, width, |t, n, _| 1e3 * n as f64 / t as f64);
print_table("MB/s", results, width, |t, _, b| b as f64 * 1e9 / 1024. / 1024. / t as f64);
println!("|{:width$}|", "", width = width + 2);
println!("{:=<width$}", "", width = width + 4);
}
Expand Down Expand Up @@ -219,11 +207,7 @@ fn print_table(
for res in results {
print!("| {:<h$}", res.name, h = h);
let (n, b) = (res.count, res.bytes);
let mut metrics = res
.times
.iter()
.map(|&t| transform(t, n, b))
.collect::<Vec<_>>();
let mut metrics = res.times.iter().map(|&t| transform(t, n, b)).collect::<Vec<_>>();
metrics.sort_by(|a, b| a.partial_cmp(b).unwrap());
for &(_, idx) in columns {
print!("{:>w$.2}", metrics[idx], w = w);
Expand All @@ -240,23 +224,23 @@ struct Input {
impl Input {
pub fn from_file(filename: impl AsRef<Path>) -> Self {
let filename = filename.as_ref();
let data = fs::read_to_string(&filename)
.unwrap()
.trim()
.lines()
.map(String::from)
.collect();
let data =
fs::read_to_string(&filename).unwrap().trim().lines().map(String::from).collect();
let name = filename.file_name().unwrap().to_str().unwrap().into();
Self { data, name }
Self {
data,
name,
}
}

pub fn from_random(gen: RandomGen, count: usize, seed: u64) -> Self {
let mut rng = Rng::with_seed(seed);
let data = iter::repeat_with(|| gen.gen(&mut rng))
.take(count)
.collect();
let data = iter::repeat_with(|| gen.gen(&mut rng)).take(count).collect();
let name = format!("{}", gen);
Self { data, name }
Self {
data,
name,
}
}

pub fn count(&self) -> usize {
Expand All @@ -281,14 +265,16 @@ impl Input {
fn main() {
let opt: Opt = StructOpt::from_args();

let methods = if !opt.only_fast_float && !matches!(&opt.command, &Cmd::All {..}) {
let methods = if !opt.only_fast_float && !matches!(&opt.command, &Cmd::All { .. }) {
Method::all().into()
} else {
vec![Method::FastFloat2]
};

let inputs = match opt.command {
Cmd::File { filename } => vec![Input::from_file(filename)],
Cmd::File {
filename,
} => vec![Input::from_file(filename)],
Cmd::Random {
gen,
count,
Expand All @@ -300,8 +286,11 @@ fn main() {
fs::write(filename, input.data.join("\n")).unwrap();
}
vec![input]
}
Cmd::All { count, seed } => {
},
Cmd::All {
count,
seed,
} => {
let mut inputs = vec![];
let data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("ext/data");
inputs.push(Input::from_file(data_dir.join("mesh.txt")));
Expand All @@ -310,7 +299,7 @@ fn main() {
inputs.push(Input::from_random(gen, count, seed))
}
inputs
}
},
};

let mut results = vec![];
Expand Down
19 changes: 19 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Requires nightly to do proper formatting.
use_small_heuristics = "Off"
use_field_init_shorthand = true
trailing_semicolon = true
newline_style = "Unix"
match_block_trailing_comma = true
empty_item_single_line = false
enum_discrim_align_threshold = 40
fn_params_layout = "Tall"
fn_single_line = false
format_macro_matchers = true
format_macro_bodies = true
imports_indent = "Block"
imports_layout = "HorizontalVertical"
indent_style = "Block"
match_arm_blocks = true
overflow_delimited_expr = true
group_imports = "StdExternalCrate"
wrap_comments = true
19 changes: 13 additions & 6 deletions src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn compute_float<F: Float>(q: i64, mut w: u64) -> AdjustedMantissa {
w <<= lz;
let (lo, hi) = compute_product_approx(q, w, F::MANTISSA_EXPLICIT_BITS + 3);
if lo == 0xFFFF_FFFF_FFFF_FFFF {
let inside_safe_exponent = (q >= -27) && (q <= 55);
let inside_safe_exponent = (-27..=55).contains(&q);
if !inside_safe_exponent {
return am_error;
}
Expand All @@ -33,7 +33,10 @@ pub fn compute_float<F: Float>(q: i64, mut w: u64) -> AdjustedMantissa {
mantissa += mantissa & 1;
mantissa >>= 1;
power2 = (mantissa >= (1_u64 << F::MANTISSA_EXPLICIT_BITS)) as i32;
return AdjustedMantissa { mantissa, power2 };
return AdjustedMantissa {
mantissa,
power2,
};
}
if lo <= 1
&& q >= F::MIN_EXPONENT_ROUND_TO_EVEN as i64
Expand All @@ -53,7 +56,10 @@ pub fn compute_float<F: Float>(q: i64, mut w: u64) -> AdjustedMantissa {
if power2 >= F::INFINITE_POWER {
return am_inf;
}
AdjustedMantissa { mantissa, power2 }
AdjustedMantissa {
mantissa,
power2,
}
}

#[inline]
Expand All @@ -67,9 +73,10 @@ fn full_multiplication(a: u64, b: u64) -> (u64, u64) {
(r as u64, (r >> 64) as u64)
}

// This will compute or rather approximate w * 5**q and return a pair of 64-bit words
// approximating the result, with the "high" part corresponding to the most significant
// bits and the low part corresponding to the least significant bits.
// This will compute or rather approximate w * 5**q and return a pair of 64-bit
// words approximating the result, with the "high" part corresponding to the
// most significant bits and the low part corresponding to the least significant
// bits.
#[inline]
fn compute_product_approx(q: i64, w: u64, precision: usize) -> (u64, u64) {
debug_assert!(q >= SMALLEST_POWER_OF_FIVE as i64);
Expand Down
Loading
Loading