Remove lossy casting in logspace
Currently `logspace` does a lossy cast from `F::Int` to `usize`. This could be problematic in the rare cases that this is called with a step count exceeding what is representable in `usize`. Resolve this by instead adding bounds so the float's integer type itself can be iterated.
This commit is contained in:
committed by
Trevor Gross
parent
e8c501861a
commit
cf58a7ce90
@@ -1,5 +1,7 @@
|
|||||||
//! A generator that produces logarithmically spaced values within domain bounds.
|
//! A generator that produces logarithmically spaced values within domain bounds.
|
||||||
|
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use libm::support::{IntTy, MinInt};
|
use libm::support::{IntTy, MinInt};
|
||||||
|
|
||||||
use crate::domain::HasDomain;
|
use crate::domain::HasDomain;
|
||||||
@@ -34,6 +36,7 @@ pub fn get_test_cases<Op>(_ctx: &CheckCtx) -> impl Iterator<Item = (Op::FTy,)>
|
|||||||
where
|
where
|
||||||
Op: MathOp + HasDomain<Op::FTy>,
|
Op: MathOp + HasDomain<Op::FTy>,
|
||||||
IntTy<Op::FTy>: TryFrom<usize>,
|
IntTy<Op::FTy>: TryFrom<usize>,
|
||||||
|
RangeInclusive<IntTy<Op::FTy>>: Iterator,
|
||||||
{
|
{
|
||||||
let domain = Op::DOMAIN;
|
let domain = Op::DOMAIN;
|
||||||
let start = domain.range_start();
|
let start = domain.range_start();
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
//! Helpful numeric operations.
|
//! Helpful numeric operations.
|
||||||
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use libm::support::{CastInto, Float};
|
use libm::support::Float;
|
||||||
|
|
||||||
use crate::{Int, MinInt};
|
use crate::{Int, MinInt};
|
||||||
|
|
||||||
@@ -214,7 +215,10 @@ fn as_ulp_steps<F: Float>(x: F) -> Option<F::SignedInt> {
|
|||||||
/// to logarithmic spacing of their values.
|
/// to logarithmic spacing of their values.
|
||||||
///
|
///
|
||||||
/// Note that this tends to skip negative zero, so that needs to be checked explicitly.
|
/// Note that this tends to skip negative zero, so that needs to be checked explicitly.
|
||||||
pub fn logspace<F: FloatExt>(start: F, end: F, steps: F::Int) -> impl Iterator<Item = F> {
|
pub fn logspace<F: FloatExt>(start: F, end: F, steps: F::Int) -> impl Iterator<Item = F>
|
||||||
|
where
|
||||||
|
RangeInclusive<F::Int>: Iterator,
|
||||||
|
{
|
||||||
assert!(!start.is_nan());
|
assert!(!start.is_nan());
|
||||||
assert!(!end.is_nan());
|
assert!(!end.is_nan());
|
||||||
assert!(end >= start);
|
assert!(end >= start);
|
||||||
@@ -225,7 +229,7 @@ pub fn logspace<F: FloatExt>(start: F, end: F, steps: F::Int) -> impl Iterator<I
|
|||||||
steps = steps.min(between); // At maximum, one step per ULP
|
steps = steps.min(between); // At maximum, one step per ULP
|
||||||
|
|
||||||
let mut x = start;
|
let mut x = start;
|
||||||
(0..=steps.cast()).map(move |_| {
|
(F::Int::ZERO..=steps).map(move |_| {
|
||||||
let ret = x;
|
let ret = x;
|
||||||
x = x.n_up(spacing);
|
x = x.n_up(spacing);
|
||||||
ret
|
ret
|
||||||
|
|||||||
Reference in New Issue
Block a user