mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
feat!: Use num-bigint for large numbers (#500)
- Supply chain: Use the popular num-bigint crate for handling large integers - Optimization: Handle f64, i64, u64 directly. These will be the most common instances of a number. OPA number semantics isn't clear. https://github.com/open-policy-agent/opa/issues/6281 As part of this change, we update the following failing tests: - A local test that relies on what 15.3/3 evaluates to. With our current change, we round in a different direction than what OPA does, but consistent with Rust. We produce 5.1000000000000005 where as the OPA test expects 5.1. There is no clear definition in Rego of what the right answer is. Moreover, policies should not rely on exact floating point value comparison. Therefore this deviations is justified. The test is patched to pass. - Another local vm test that exercised 1.1 + 2.2 - Another local vm test that exercises 5.5 - 2.2 - An OPA test that expects that a large integer number say 10e308 is printed in exponent notation. num-bigint does not print using scientific notation and instead prints all the digits. The benefit of preserving this compatibility is not clear. We skip this test. - Doc tests that exercised handling floating point numbers with more than 15 (what f64 supports) digits of precision. There is no usecase for this scenario. The tests are updated to reflect the behavior. Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
14deaaa5b6
commit
a8a3a9809b
45
src/value.rs
45
src/value.rs
@@ -575,35 +575,32 @@ impl From<f64> for Value {
|
||||
/// # use regorus::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// assert_eq!(
|
||||
/// Value::from(3.141592653589793),
|
||||
/// Value::from(3.5f64),
|
||||
/// Value::from_numeric_string("3.5")?);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Value::Number`] stores floating-point values as `f64`, so it inherits the same
|
||||
/// ~15-digit precision limit. Adding additional digits to either the literal or a parsed
|
||||
/// numeric string causes both to round to the same `f64` value.
|
||||
/// ```
|
||||
/// # use regorus::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let from_float = Value::from(3.141592653589793238462f64);
|
||||
/// let from_string = Value::from_numeric_string("3.141592653589793238462")?;
|
||||
/// assert_eq!(from_float, from_string);
|
||||
///
|
||||
/// // All representations round to approximately 15 digits.
|
||||
/// assert_eq!(
|
||||
/// from_float,
|
||||
/// Value::from_numeric_string("3.141592653589793")?);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Note, f64 can store only around 15 digits of precision whereas [`Value::Number`]
|
||||
/// can store arbitrary precision. Adding an extra digit to the f64 literal in the above
|
||||
/// example causes loss of precision and the Value created from f64 does not match the
|
||||
/// Value parsed from numeric string (which is more precise).
|
||||
/// ```
|
||||
/// # use regorus::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// // The last digit is lost in f64.
|
||||
/// assert_ne!(
|
||||
/// Value::from(3.1415926535897932),
|
||||
/// Value::from_numeric_string("3.141592653589793232")?);
|
||||
///
|
||||
/// // The value, in this case is equal to parsing the json number with last digit omitted.
|
||||
/// assert_ne!(
|
||||
/// Value::from(3.1415926535897932),
|
||||
/// Value::from_numeric_string("3.14159265358979323")?);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// If precision is important, it is better to construct numeric values from strings instead
|
||||
/// of f64 when possible.
|
||||
/// See [Value::from_numeric_string]
|
||||
/// If additional precision is required, keep the raw data as strings or use an external
|
||||
/// arbitrary-precision numeric type before converting it into [`Value`].
|
||||
fn from(n: f64) -> Self {
|
||||
Value::Number(Number::from(n))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user