A rustc plugin to check for numerical instability

Overview

Herbie lint for Rust Build Status Crates.io License

What

This plugin can add warnings or errors to your crate when using a numerically unstable floating point expression.

Quick example of what you can get when compiling tests/compile-fail/general/test.rs:

test.rs:40:5: 40:18 warning: Numerically unstable expression, #[warn(herbie)] on by default
test.rs:40     (a/b + c) * b;
               ^~~~~~~~~~~~~
test.rs:40:5: 40:18 help: Try this
test.rs:       (c * b) + a;
test.rs:67:5: 67:23 warning: Numerically unstable expression, #[warn(herbie)] on by default
test.rs:67     (a*a + b*b).sqrt();
               ^~~~~~~~~~~~~~~~~~
test.rs:67:5: 67:23 help: Try this
test.rs:       a.hypot(b);
test.rs:155:5: 155:30 warning: Numerically unstable expression, #[warn(herbie)] on by default
test.rs:155     (a+b).sin() - (a+b).cos();
                ^~~~~~~~~~~~~~~~~~~~~~~~~
test.rs:155:5: 155:30 help: Try this
test.rs:        (b.sin() * (a.sin() + a.cos())) - ((a.cos() - a.sin()) * b.cos());

As you can see, it will report numerically unstable expressions, and suggest a (sometimes over-parenthesized) more stable correction.

Usage

Plugin

This is a rustc plugin, to use it, you need a nightly Rust.

You need a database of possible corrections for this plugin to work. The database format is the same as Herbie GHC Plugin (for Haskell) from which this plugin is inspired so this file should work. Just put it in the same directory you call cargo or rustc from.

Add in your Cargo.toml:

[dependencies]
herbie-lint = "{{VERSION}}"

and in your crate:

#![feature(plugin)]
#![plugin(herbie_lint)]

See clippy's Usage section if you want to know more and if you want more Rust lints.

Configuration

If you don't want the plugin to lint a particular function or method, you can mark it with the #[herbie_ignore] attribute:

fn foo(a: f64, b: f64, c: f64) -> f64 {
    (a/b + c) * b
    // This will suggest to use “(c * b) + a” instead.
}

#[herbie_ignore]
fn bar(a: f64, b: f64, c: f64) -> f64 {
    (a/b + c) * b
    // This won't.
}

You can also put a Herbie.toml file next to your Cargo.toml with the following fields:

# Path to the database.
db_path = "Herbie.db"

# The seed used by Herbie. If not provided, a fixed seed will be used. Fixing
# the seed ensures deterministic builds.
herbie_seed = "#(1461197085 2376054483 1553562171 1611329376 2497620867 2308122621)"

# Allow the plugin to call Herbie on unknown expressions. Positive results from
# Herbie will be cached in the database. WARNING: Herbie is slow.
# If ‘true’, the plugin will fail if it cannot find the executable.
# If ‘false’, the plugin will not try to run Herbie.
# By default, the plugin will call the executable only if it's found, but won't
# complain otherwise.
use_herbie = false

# Maximum time in seconds that Herbie is allowed to play with an expression. If
# null, allow Herbie to run indefinitely. Default is two minutes.
timeout = 120

More information about calling Herbie can be found in the wiki.

Acknowledgment

Thanks to @llogiq for the idea.

You might also like...
Cargo-eval - A cargo plugin to quickly evaluate some Rust source code.

cargo eval A cargo plugin to quickly evaluate some Rust source code. Installation $ cargo install --git https://github.com/timClicks/cargo-eval.git Us

Cargo-about - 📜 Cargo plugin to generate list of all licenses for a crate 🦀

📜 cargo-about Cargo plugin for generating a license listing for all dependencies of a crate See the book 📕 for in-depth documentation. Please Note:

Binary Ninja plugin written in Rust to automatically apply symbol information from split debug info on Linux.

Load Symbols Binary Ninja plugin written in Rust to automatically apply symbol information from split debug info on Linux. Requirements Last tested wi

A plugin system for the Rhai embedded scripting language.

Rhai Dylib This crate exposes a simple API to load dylib Rust crates in a Rhai engine using Rhai modules. 🚧 This is a work in progress, the API is su

A Faster(⚡)  formatter, linter, bundler, and more for JavaScript, TypeScript, JSON, HTML, Markdown, and CSS Lapce Plugin
A Faster(⚡) formatter, linter, bundler, and more for JavaScript, TypeScript, JSON, HTML, Markdown, and CSS Lapce Plugin

Lapce Plugin for Rome Lapce-rome is a Lapce plugin for rome, The Rome is faster ⚡ , A formatter, linter, compiler, bundler, and more for JavaScript, T

Lapce plugin for the Php language.

lapce-php-intelephense Lapce plugin for the Php language. Prerequisites Install Intelephense, typically by running: $ npm i intelephense -g Settings S

Julia plugin for the Lapce Editor (using LanguageServer.jl)

Lapce Julia (LanguageServer) Lapce plugin for the Julia language powered by LanguageServer.jl Pre-requisites Make sure you have the julia binary on PA

Grid-based drum sequencer plugin as MIDI FX in CLAP/VST3 format
Grid-based drum sequencer plugin as MIDI FX in CLAP/VST3 format

dr-seq Grid-based drum sequencer plugin as MIDI FX in CLAP/VST3 format. WARNING: This project is in a very early state. So there is no guarantee for a

Neovim plugin for moving lines up and down, written in Rust

Moveline.nvim Moveline is a simple plugin for moving lines up and down. It's written in Rust using my library nvim-utils. Installation Moveline can be

Comments
  • Herbie is advising the use of log1p, which doesn't exist

    Herbie is advising the use of log1p, which doesn't exist

    I've just run Herbie on some floating-point operations using Nightly, and I get this:

    src/lib.rs:232:67: 232:85 warning: Numerically unstable expression, #[warn(herbie)] on by default
    src/lib.rs:232     let M2 = (3. * n + 3. * n.powi(2) + (21. / 8.) * n.powi(3)) * (lat - lat0).sin() *
    src/lib.rs:232:67: 232:85 help: Try this
    src/lib.rs:        let M2 = (3. * n + 3. * n.powi(2) + (21. / 8.) * n.powi(3)) * ((lat.sin() * lat0.cos()) - (lat.cos() * lat0.sin())).log1p().expm1() *
    

    Which is great! But there's no log1p function in Rust as far as I can see…it exists in the GSL crate (which is a wrapper around GNU GSL), but that's not obvious:

    src/lib.rs:232:121: 232:128 error: no method named `log1p` found for type `f64` in the current scope
    
    opened by urschrei 4
  • Any chance of an update?

    Any chance of an update?

    This no longer compiles and I wondered if you'd thought about updating it. I've not done any compiler plugin things, but i might try have a look if you're not.

    opened by dten 2
  • Run it on “a ton of crates in the ecosystem”

    Run it on “a ton of crates in the ecosystem”

    In order to test the plugin, feed a Rust-specific database and improve other crates, the plugin should be tried on lots of crates in the ecosystem.

    Some ideas of crates with potentially lots of floating point expression (from a quick search of "math" on crates.io, so many crates are missing, and all of the following might not be relevant):

    • [ ] ncollide
    • [ ] nphysics
    • [x] cgmath
    • [x] closed01
    • [x] dumbmath
    • [x] fast-math
    • [x] fiz-math
    • [x] glm
    • [x] image
    • [x] imageproc
    • [x] nalgebra
    • [x] noise
    • [x] vecmath

    Don't hesitate to suggest more if you know some crates that should be on the list :smile:

    opened by mcarton 2
Owner
Martin Carton
Martin Carton
Unborrowed Rust Compiler (rustc without a borrowchecker)

ubrustc: Unborrowed rustc This is rustc with the borrow checker disabled. I wrote it in like, 30 minutes because this tweet made me laugh. Example //

Thom Chiovoloni 57 Apr 20, 2023
Check the reproducibility status of your Arch Linux packages (read-only mirror)

arch-repro-status A CLI tool for querying the reproducibility status of the Arch Linux packages using data from a rebuilderd instance such as reproduc

Arch Linux 12 Nov 16, 2022
languagetool-code-comments integrates the LanguageTool API to parse, spell check, and correct the grammar of your code comments!

languagetool-code-comments integrates the LanguageTool API to parse, spell check, and correct the grammar of your code comments! Overview Install MacO

Dustin Blackman 17 Dec 25, 2022
'apk-yara-checker' is a little CLI tool written in Rust to check Yara rules against a folder of APK files.

apk-yara-checker 'apk-yara-checker' is a little CLI tool written in Rust to check Yara rules against a folder of APK files. You have to pass the folde

alberto__segura 15 Oct 5, 2022
CIEBII - Check if every bit is intact

CIEBII Checks If Every Byte Is Intact CIEBII is an image file format that checks if every single byte is intact. What does it do if it finds that a by

Codingsquirrel 2 Oct 7, 2022
Check if the process is running inside Windows Subsystem for Linux (Bash on Windows)

is-wsl Check if the process is running inside Windows Subsystem for Linux (Bash on Windows) Inspired by sindresorhus/is-wsl and made for Rust lang. Ca

Sean Larkin 6 Jan 31, 2023
Check a folder for dirty git repositories, forgotten branches and commits

dg - find dirty git repos Ever forgot to push a commit or lost your work because you assumed it was pushed to Github but it wasn't? dg finds local git

Dotan J. Nahum 11 Mar 19, 2023
Tool to check Nixpkgs' pkgs/by-name directory

Nixpkgs pkgs/by-name checker This repository implements a program to check Nixpkgs' pkgs/by-name directory as part of RFC 140. See CONTRIBUTING.md for

Nix/Nixpkgs/NixOS 8 May 6, 2024
A cargo plugin to shrink cargo's output

cargo single-line A simple cargo plugin that shrinks the visible cargo output to a single line (okay, in the best case scenario). In principle, the pl

Denis 5 Oct 30, 2022
Vim plugin to quickly parse strings into arrays.

butcher Vim plugin to quickly parse strings into arrays. It is painful to write arrays in any programming language, so butcher makes it easy for you.

null 5 Dec 31, 2021