Skip to content

Add fN::replace_nan #787

@orlp

Description

@orlp

Proposal

Problem statement

It is common to need to deal with NaN in some way in floating point code. It is a uniquely problematic value. Infinities are typically easy to handle through clamping/comparisons, but NaN always needs its own path unless being exceptionally tricky.

Motivating examples or use cases

Searching for if ident.is_nan() gives a lot of examples that would be written cleaner with replace_nan:

fn compute_bar_units(mut percent: f64, total_chars: usize) -> usize {
    if percent.is_nan() {
        percent = 0.0;
    }
    (percent.round() * total_chars as f64 / 100.0).ceil() as usize

This could simply be

fn compute_bar_units(percent: f64, total_chars: usize) -> usize {
    (percent.replace_nan(0.0).round() * total_chars as f64 / 100.0).ceil() as usize

Or

let potential = -y * a.ln() - (1.0  - y) * (1.0 -  a).ln();
result += if potential.is_nan() { 0.0 } else { potential };

could just be

result += (-y * a.ln() - (1.0  - y) * (1.0 -  a).ln()).replace_nan(0.0);

Quite often when you are checking for is_nan() and then doing something different, you could just unconditionally do something after replacing NaN with some value (often, but not always, 0).

Solution sketch

Add the following function to all float types:

impl fN {
    /// If `self` is a NaN it is replaced with the given value,
    /// otherwise `self` is returned unchanged.
    fn replace_nan(self, value: Self) -> Self {
        if self.is_nan() { value } else { self }
    }
}

Alternatives

Simply write an if statement. However this often breaks arithmetic chains because there are two references to self, meaning you have to assign to (an otherwise often meaningless) temporary variable, or use mutability.

Links and related work

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions