From 2f04c172fe74981be82149823d96574f7ff4383f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Sun, 12 Sep 2021 14:12:53 +0300 Subject: [PATCH] Add floating point support for ranges --- crates/nu-protocol/src/value/range.rs | 41 +++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/crates/nu-protocol/src/value/range.rs b/crates/nu-protocol/src/value/range.rs index ff138e4af6..2832d09b2b 100644 --- a/crates/nu-protocol/src/value/range.rs +++ b/crates/nu-protocol/src/value/range.rs @@ -1,3 +1,5 @@ +use std::cmp::Ordering; + use crate::{ ast::{RangeInclusion, RangeOperator}, *, @@ -150,31 +152,46 @@ impl RangeIterator { } } +// Compare two floating point numbers. The decision interval for equality is dynamically scaled +// based on the value being compared. +fn compare_floats(val: f64, other: f64) -> Option { + let prec = val * f64::EPSILON; + + if (other - val).abs() < prec.abs() { + return Some(Ordering::Equal); + } + + val.partial_cmp(&other) +} + impl Iterator for RangeIterator { type Item = Value; fn next(&mut self) -> Option { - use std::cmp::Ordering; if self.done { return None; } let ordering = if matches!(self.end, Value::Nothing { .. }) { - Ordering::Less + Some(Ordering::Less) } else { match (&self.curr, &self.end) { - (Value::Int { val: curr, .. }, Value::Int { val: end, .. }) => curr.cmp(end), - // (Value::Float { val: curr, .. }, Value::Float { val: end, .. }) => curr.cmp(end), - // (Value::Float { val: curr, .. }, Value::Int { val: end, .. }) => curr.cmp(end), - // (Value::Int { val: curr, .. }, Value::Float { val: end, .. }) => curr.cmp(end), - _ => { - self.done = true; - return Some(Value::Error { - error: ShellError::CannotCreateRange(self.span), - }); - } + (Value::Int { val: curr, .. }, Value::Int { val: end, .. }) => Some(curr.cmp(end)), + (Value::Float { val: curr, .. }, Value::Float { val: end, .. }) => compare_floats(*curr, *end), + (Value::Float { val: curr, .. }, Value::Int { val: end, .. }) => compare_floats(*curr, *end as f64), + (Value::Int { val: curr, .. }, Value::Float { val: end, .. }) => compare_floats(*curr as f64, *end), + _ => None, } }; + let ordering = if let Some(ord) = ordering { + ord + } else { + self.done = true; + return Some(Value::Error { + error: ShellError::CannotCreateRange(self.span), + }); + }; + let desired_ordering = if self.moves_up { Ordering::Less } else {