rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.77k stars 12.65k forks source link

<f64> <Into<f64>> addition #130882

Closed JeromeSchmied closed 3 weeks ago

JeromeSchmied commented 3 weeks ago

I tried this code:

/// coordinates
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
pub struct Coord {
    /// latitude: north-south
    lat: f64,
    /// longitude: east-west
    lon: f64,
}
impl Coord {
    pub fn new(lat: impl Into<f64>, lon: impl Into<f64>) -> Self {
        let lat = lat.into();
        let lon = lon.into();
        assert!((-90. ..=90.).contains(&lat));
        assert!((-180. ..=180.).contains(&lon));
        Self { lat, lon }
    }
    pub fn with_lat(self, lat: impl Into<f64>) -> Self {
        Self::new(lat, self.lon)
    }
    pub fn with_lon(self, lon: impl Into<f64>) -> Self {
        Self::new(self.lat, lon)
    }
    pub fn add_to_lat(self, lat: impl Into<f64>) -> Self {
        self.with_lat(self.lat + lat.into())
    }
    pub fn add_to_lon(self, lon: impl Into<f64>) -> Self {
        self.with_lon(self.lon + lon.into())
    }

    /// truncate both latitude and longitude
    pub fn trunc(&self) -> (i32, i32) {
        (self.lat.trunc() as i32, self.lon.trunc() as i32)
    }
}
impl<F1: Into<f64>, F2: Into<f64>> From<(F1, F2)> for Coord {
    fn from(value: (F1, F2)) -> Self {
        let (lat, lon) = (value.0.into(), value.1.into());
        Coord { lat, lon }
    }
}

#[test]
fn correct_coord_7() {
    let c: Coord = (90, -180.).into();
    assert_eq!(Coord::new(90, -180), c);
    let c = c.add_to_lat(-20.3252);
    assert_eq!(Coord::new(69.6748, -180), c);
    let c = c.add_to_lon(35.342);
    assert_eq!(Coord::new(69.6748, -144.658), c);
}
full code

```rust //! A performant [srtm](https://www.earthdata.nasa.gov/sensors/srtm) reader for `.hgt` files. //! //! # Usage //! //! ```rust //! use srtm_reader::Tile; //! use std::path::PathBuf; //! //! // the actual elevation of Veli Brig, 263m //! const TRUE_ELEV: i16 = 263; //! // the coordinates of Veli Brig, actual elevation: 263m //! let coord = (44.4480403, 15.0733053); //! // we get the filename, that shall include the elevation data for this `coord` //! let filename = srtm_reader::get_filename(coord); //! // in this case, the filename will be: //! assert_eq!(filename, "N44E015.hgt"); //! // load the srtm tile: .hgt file //! let tile = Tile::from_file(filename).unwrap(); //! // and finally, retrieve our elevation for Veli Brig //! let elevation = tile.get(coord); //! // test with a ± 5m //! assert!((TRUE_ELEV - 5..TRUE_ELEV + 5).contains(&elevation)); //! println!("Veli Brig:\n\t- coordinates: {coord:?}\n\t- elevation\n\t\t- actual: {TRUE_ELEV}m\n\t\t- calculated: {elevation}m"); //! ``` use byteorder::{BigEndian, ReadBytesExt}; use std::fs::{self, File}; use std::io::{self, BufReader, Read}; use std::path::Path; /// this many rows and columns are there in a standard SRTM1 file const EXTENT: usize = 3600; /// the available resulutions of the SRTM data, in arc seconds #[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Debug, Default)] pub enum Resolution { SRTM05, #[default] SRTM1, SRTM3, } impl Resolution { /// the number of rows and columns in an SRTM data file of [`Resolution`] pub const fn extent(&self) -> usize { match self { Resolution::SRTM05 => EXTENT * 2 + 1, Resolution::SRTM1 => EXTENT + 1, Resolution::SRTM3 => EXTENT / 3 + 1, } } /// total file length in BigEndian, total file length in bytes is [`Resolution::total_len()`] * 2 pub const fn total_len(&self) -> usize { self.extent().pow(2) } } /// the SRTM tile, which contains the actual elevation data #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct Tile { pub latitude: i32, pub longitude: i32, pub resolution: Resolution, pub data: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Error { ParseLatLong, Filesize, Read, } /// coordinates #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)] pub struct Coord { /// latitude: north-south lat: f64, /// longitude: east-west lon: f64, } impl Coord { pub fn new(lat: impl Into, lon: impl Into) -> Self { let lat = lat.into(); let lon = lon.into(); assert!((-90. ..=90.).contains(&lat)); assert!((-180. ..=180.).contains(&lon)); Self { lat, lon } } pub fn with_lat(self, lat: impl Into) -> Self { Self::new(lat, self.lon) } pub fn with_lon(self, lon: impl Into) -> Self { Self::new(self.lat, lon) } pub fn add_to_lat(self, lat: impl Into) -> Self { self.with_lat(self.lat + lat.into()) } pub fn add_to_lon(self, lon: impl Into) -> Self { self.with_lon(self.lon + lon.into()) } /// truncate both latitude and longitude pub fn trunc(&self) -> (i32, i32) { (self.lat.trunc() as i32, self.lon.trunc() as i32) } } impl, F2: Into> From<(F1, F2)> for Coord { fn from(value: (F1, F2)) -> Self { let (lat, lon) = (value.0.into(), value.1.into()); Coord { lat, lon } } } impl Tile { fn new_empty(lat: i32, lon: i32, res: Resolution) -> Tile { Tile { latitude: lat, longitude: lon, resolution: res, data: Vec::new(), } } /// read an srtm: `.hgt` file, and create a [`Tile`] if possible pub fn from_file>(path: P) -> Result { let (lat, lon) = get_lat_long(&path)?; let res = get_resolution(&path).ok_or(Error::Filesize)?; // eprintln!("resolution: {res:?}"); let file = File::open(&path).map_err(|_| Error::Read)?; // eprintln!("file: {file:?}"); let reader = BufReader::new(file); let mut tile = Tile::new_empty(lat, lon, res); tile.data = parse(reader, tile.resolution).map_err(|e| { eprintln!("parse error: {e:#?}"); Error::Read })?; Ok(tile) } /// the maximum height that this [`Tile`] contains pub fn max_height(&self) -> i16 { *(self.data.iter().max().unwrap()) } /// get lower-left corner's latitude and longitude /// it's needed for [`Tile::get_offset()`] fn get_origin(&self, coord: Coord) -> Coord { let lat = coord.lat.trunc() + 1.; // The latitude of the lower-left corner of the tile let lon = coord.lon.trunc(); // The longitude of the lower-left corner of the tile Coord { lat, lon } } /// calculate where this `coord` is located in this [`Tile`] fn get_offset(&self, coord: Coord) -> (usize, usize) { let origin = self.get_origin(coord); // eprintln!("origin: ({}, {})", origin.0, origin.1); let extent = self.resolution.extent() as f64; let row = ((origin.lat - coord.lat) * extent) as usize; let col = ((coord.lon - origin.lon) * extent) as usize; (row, col) } /// get the elevation of this `coord` from this [`Tile`] /// /// # Panics /// If this [`Tile`] doesn't contain `coord`'s elevation /// *NOTE*: shouldn't happen if [`get_filename()`] was used pub fn get>(&self, coord: C) -> i16 { let coord: Coord = coord.into(); let offset = self.get_offset(coord); let lat = coord.lat.trunc() as i32; let lon = coord.lon.trunc() as i32; assert!( self.latitude <= lat, "hgt lat: {}, coord lat: {lat}", self.latitude ); assert!( self.longitude <= lon, "hgt lon: {}, coord lon: {lon}", self.longitude ); // eprintln!("offset: ({}, {})", offset.1, offset.0); self.get_at_offset(offset.1, offset.0) } fn get_at_offset(&self, x: usize, y: usize) -> i16 { self.data[self.idx(x, y)] } fn idx(&self, x: usize, y: usize) -> usize { assert!(x < self.resolution.extent() && y < self.resolution.extent()); y * self.resolution.extent() + x } } /// guess the resolution of the file at `path` fn get_resolution>(path: P) -> Option { let from_metadata = |m: fs::Metadata| { let len = m.len() as usize; // eprintln!("len: {len}"); if len == Resolution::SRTM05.total_len() * 2 { Some(Resolution::SRTM05) } else if len == Resolution::SRTM1.total_len() * 2 { Some(Resolution::SRTM1) } else if len == Resolution::SRTM3.total_len() * 2 { Some(Resolution::SRTM3) } else { eprintln!("unknown filesize: {}", len); None } }; fs::metadata(path) .inspect_err(|e| eprintln!("error: {e:#?}")) .ok() .and_then(from_metadata) } // FIXME: Better error handling. fn get_lat_long>(path: P) -> Result<(i32, i32), Error> { let stem = path.as_ref().file_stem().ok_or(Error::ParseLatLong)?; let desc = stem.to_str().ok_or(Error::ParseLatLong)?; if desc.len() != 7 { return Err(Error::ParseLatLong); } let get_char = |n| desc.chars().nth(n).ok_or(Error::ParseLatLong); let lat_sign = if get_char(0)? == 'N' { 1 } else { -1 }; let lat: i32 = desc[1..3].parse().map_err(|_| Error::ParseLatLong)?; let lon_sign = if get_char(3)? == 'E' { 1 } else { -1 }; let lon: i32 = desc[4..7].parse().map_err(|_| Error::ParseLatLong)?; Ok((lat_sign * lat, lon_sign * lon)) } /// get the name of the file, which shall include this `coord`s elevation /// /// # Usage /// /// ```rust /// // the `coord`inate, whe want the elevation for /// let coord = (87.235, 10.4234423); /// // this convenient function gives us the filename for /// // any `coord`inate, that is `impl Into` /// // which is true for this tuple /// let filename = srtm_reader::get_filename(coord); /// assert_eq!(filename, "N87E010.hgt"); /// ``` pub fn get_filename>(coord: C) -> String { let coord: Coord = coord.into(); let lat_ch = if coord.lat >= 0. { 'N' } else { 'S' }; let lon_ch = if coord.lon >= 0. { 'E' } else { 'W' }; let lat = (coord.lat.trunc() as i32).abs(); let lon = (coord.lon.trunc() as i32).abs(); format!( "{lat_ch}{}{lat}{lon_ch}{}{lon}.hgt", if lat < 10 { "0" } else { "" }, if lon < 10 { "00" } else if lon < 100 { "0" } else { "" } ) } fn parse(reader: R, res: Resolution) -> io::Result> { let mut reader = reader; let mut data = Vec::new(); // eprintln!("total size: {}", res.total_size()); for _ in 0..res.total_len() { // eprint!("{i} "); let h = reader.read_i16::()?; data.push(h); } Ok(data) } #[cfg(test)] mod tests { use super::*; use std::path::Path; #[test] fn parse_latitute_and_longitude() { let ne = Path::new("N35E138.hgt"); assert_eq!(get_lat_long(ne).unwrap(), (35, 138)); let nw = Path::new("N35W138.hgt"); assert_eq!(get_lat_long(nw).unwrap(), (35, -138)); let se = Path::new("S35E138.hgt"); assert_eq!(get_lat_long(se).unwrap(), (-35, 138)); let sw = Path::new("S35W138.hgt"); assert_eq!(get_lat_long(sw).unwrap(), (-35, -138)); } #[test] fn total_file_sizes() { assert_eq!(103_708_802 / 2, Resolution::SRTM05.total_len()); assert_eq!(25_934_402 / 2, Resolution::SRTM1.total_len()); assert_eq!(2_884_802 / 2, Resolution::SRTM3.total_len()); } #[test] fn extents() { assert_eq!(7201, Resolution::SRTM05.extent()); assert_eq!(3601, Resolution::SRTM1.extent()); assert_eq!(1201, Resolution::SRTM3.extent()); } #[test] #[should_panic] fn wrong_coord_0() { let _ = Coord::new(-190, 42.4); } #[test] #[should_panic] fn wrong_coord_1() { let _ = Coord::new(180, -42.4); } #[test] #[should_panic] fn wrong_coord_2() { let _ = Coord::new(-90., 181.); } #[test] #[should_panic] fn wrong_coord_3() { let _ = Coord::new(90., -180.00001); } #[test] fn correct_coord_0() { let _ = Coord::new(-90, 180); } #[test] fn correct_coord_1() { let _ = Coord::new(90, -180); } #[test] fn correct_coord_2() { let c = Coord::new(90, -180).with_lon(-85.7); assert_eq!(Coord::new(90, -85.7), c); } #[test] fn correct_coord_3() { let c = Coord::new(90, -180).with_lat(0.3); assert_eq!(Coord::new(0.3, -180), c); } #[test] fn correct_coord_4() { let c = Coord::new(90, -180).with_lat(0.3).with_lon(83.3); assert_eq!(Coord::new(0.3, 83.3), c); } #[test] fn correct_coord_5() { let c: Coord = (90, -180).into(); let c = c.with_lat(0.3).with_lon(83.3); assert_eq!(Coord::new(0.3, 83.3), c); } #[test] fn correct_coord_6() { let c: Coord = (90, -180).into(); let c = c.with_lat(0.3).with_lon(83.3); assert_eq!(Coord::new(0.3, 83.3), c); } #[test] fn correct_coord_7() { let c: Coord = (90, -180.).into(); assert_eq!(Coord::new(90, -180), c); let c = c.add_to_lat(-20.3252); assert_eq!(Coord::new(69.6748, -180), c); let c = c.add_to_lon(35.342); assert_eq!(Coord::new(69.6748, -144.658), c); } #[test] fn correct_coord_8() { let c: Coord = (-90, 180).into(); let c = c.add_to_lat(0.3252).add_to_lon(-3.2); assert_eq!(Coord::new(-89.6748, 176.8), c); } fn coords() -> [Coord; 3] { [(45, 1.4).into(), (-2.3, 87).into(), (35, -7).into()] } #[test] fn file_names() { let fnames = coords() .iter() .map(|c| get_filename(*c)) .collect::>(); assert_eq!(fnames[0], "N45E001.hgt"); assert_eq!(fnames[1], "S02E087.hgt"); assert_eq!(fnames[2], "N35W007.hgt"); } #[test] fn read() { let coord = Coord::new(44.4480403, 15.0733053); let fname = get_filename(coord); let tile = Tile::from_file(fname).unwrap(); assert_eq!(tile.latitude, 44); assert_eq!(tile.longitude, 15); assert_eq!(tile.resolution, Resolution::SRTM1); assert_eq!(tile.data.len(), Resolution::SRTM1.total_len()); let elev = tile.get(coord); assert_eq!(elev, 258); } } ```

I expected to see this happen: cargo test without errors

Instead, this happened:

failures:

---- tests::correct_coord_7 stdout ----
thread 'tests::correct_coord_7' panicked at src/lib.rs:371:9:
assertion `left == right` failed
  left: Coord { lat: 69.6748, lon: -144.658 }
 right: Coord { lat: 69.6748, lon: -144.65800000000002 }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
    tests::correct_coord_7

Meta

rustc --version --verbose:

rustc 1.81.0 (eeb90cda1 2024-09-04)
binary: rustc
commit-hash: eeb90cda1969383f56a2637cbd3037bdf598841c
commit-date: 2024-09-04
host: x86_64-unknown-linux-gnu
release: 1.81.0
LLVM version: 18.1.7
Backtrace

``` RUST_BACKTRACE=full cargo t Finished `test` profile [unoptimized + debuginfo] target(s) in 0.00s Running unittests src/lib.rs (target/debug/deps/srtm_reader-6f9846fbd3702ba2) running 18 tests test tests::correct_coord_2 ... ok test tests::correct_coord_3 ... ok test tests::correct_coord_5 ... ok test tests::correct_coord_1 ... ok test tests::correct_coord_4 ... ok test tests::correct_coord_0 ... ok test tests::correct_coord_6 ... ok test tests::correct_coord_8 ... ok test tests::extents ... ok test tests::file_names ... ok test tests::parse_latitute_and_longitude ... ok test tests::total_file_sizes ... ok test tests::correct_coord_7 ... FAILED test tests::wrong_coord_0 - should panic ... ok test tests::wrong_coord_1 - should panic ... ok test tests::wrong_coord_2 - should panic ... ok test tests::wrong_coord_3 - should panic ... ok test tests::read ... ok failures: ---- tests::correct_coord_7 stdout ---- thread 'tests::correct_coord_7' panicked at src/lib.rs:371:9: assertion `left == right` failed left: Coord { lat: 69.6748, lon: -144.658 } right: Coord { lat: 69.6748, lon: -144.65800000000002 } stack backtrace: 0: 0x5dc7dc088955 - std::backtrace_rs::backtrace::libunwind::trace::h649ab3318d3445c5 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/../../backtrace/src/backtrace/libunwind.rs:116:5 1: 0x5dc7dc088955 - std::backtrace_rs::backtrace::trace_unsynchronized::hf4bb60c3387150c3 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5 2: 0x5dc7dc088955 - std::sys::backtrace::_print_fmt::hd9186c800e44bd00 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/backtrace.rs:65:5 3: 0x5dc7dc088955 - ::fmt::h1b9dad2a88e955ff at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/backtrace.rs:40:26 4: 0x5dc7dc0af90b - core::fmt::rt::Argument::fmt::h351a7824f737a6a0 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/fmt/rt.rs:173:76 5: 0x5dc7dc0af90b - core::fmt::write::h4b5a1270214bc4a7 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/fmt/mod.rs:1182:21 6: 0x5dc7dc085c3f - std::io::Write::write_fmt::h9d1e399061051a36 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/io/mod.rs:1827:15 7: 0x5dc7dc08a171 - std::sys::backtrace::BacktraceLock::print::h68d41b51481bce5c at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/backtrace.rs:43:9 8: 0x5dc7dc08a171 - std::panicking::default_hook::{{closure}}::h96ab15e9936be7ed at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:269:22 9: 0x5dc7dc089d18 - std::panicking::default_hook::h3cacb9c27561ad33 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:293:9 10: 0x5dc7dc05603a - as core::ops::function::Fn>::call::hd212b1446b2b2077 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/alloc/src/boxed.rs:2084:9 11: 0x5dc7dc05603a - test::test_main::{{closure}}::hd15ff34f3f68988b at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/test/src/lib.rs:136:21 12: 0x5dc7dc08aa7f - as core::ops::function::Fn>::call::hce7569f4ca5d1b64 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/alloc/src/boxed.rs:2084:9 13: 0x5dc7dc08aa7f - std::panicking::rust_panic_with_hook::hfe205f6954b2c97b at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:808:13 14: 0x5dc7dc08a6a7 - std::panicking::begin_panic_handler::{{closure}}::h6cb44b3a50f28c44 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:674:13 15: 0x5dc7dc088e19 - std::sys::backtrace::__rust_end_short_backtrace::hf1c1f2a92799bb0e at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/backtrace.rs:168:18 16: 0x5dc7dc08a334 - rust_begin_unwind at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:665:5 17: 0x5dc7dc0ae073 - core::panicking::panic_fmt::h3d8fc78294164da7 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panicking.rs:74:14 18: 0x5dc7dc0ae35e - core::panicking::assert_failed_inner::h19a8ffbd06abbe27 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panicking.rs:410:17 19: 0x5dc7dc01380e - core::panicking::assert_failed::hac521a992a1b890c at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panicking.rs:365:5 20: 0x5dc7dc01d089 - srtm_reader::tests::correct_coord_7::h08800787e54c2971 at /home/jero/code/rust/projects/garmin/srtm_reader/src/lib.rs:371:9 21: 0x5dc7dc01ac87 - srtm_reader::tests::correct_coord_7::{{closure}}::hb481e2337a57507e at /home/jero/code/rust/projects/garmin/srtm_reader/src/lib.rs:365:25 22: 0x5dc7dc015f16 - core::ops::function::FnOnce::call_once::h92dd2f6e95fff18b at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/ops/function.rs:250:5 23: 0x5dc7dc05a67b - core::ops::function::FnOnce::call_once::h81f56a195fe4862e at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/ops/function.rs:250:5 24: 0x5dc7dc05a67b - test::__rust_begin_short_backtrace::h919c79c8b896f9e2 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/test/src/lib.rs:624:18 25: 0x5dc7dc059f25 - test::run_test_in_process::{{closure}}::h7b3d5751c5b4dd75 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/test/src/lib.rs:647:60 26: 0x5dc7dc059f25 - as core::ops::function::FnOnce<()>>::call_once::hdabd61465e4dbd80 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panic/unwind_safe.rs:272:9 27: 0x5dc7dc059f25 - std::panicking::try::do_call::hc813c79fd64b0a90 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:557:40 28: 0x5dc7dc059f25 - std::panicking::try::h055c5de7e7bfc209 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:521:19 29: 0x5dc7dc059f25 - std::panic::catch_unwind::h4265d6525195c807 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panic.rs:350:14 30: 0x5dc7dc059f25 - test::run_test_in_process::he72c277a35f96567 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/test/src/lib.rs:647:27 31: 0x5dc7dc059f25 - test::run_test::{{closure}}::h974e632522c0fbcf at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/test/src/lib.rs:568:43 32: 0x5dc7dc020ca4 - test::run_test::{{closure}}::hdc2c89ce8b601dda at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/test/src/lib.rs:598:41 33: 0x5dc7dc020ca4 - std::sys::backtrace::__rust_begin_short_backtrace::h342cb8e53aeb2076 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/backtrace.rs:152:18 34: 0x5dc7dc0243d2 - std::thread::Builder::spawn_unchecked_::{{closure}}::{{closure}}::h67b1b5c1709ad95b at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/thread/mod.rs:538:17 35: 0x5dc7dc0243d2 - as core::ops::function::FnOnce<()>>::call_once::hd8c7a030ea8b7676 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panic/unwind_safe.rs:272:9 36: 0x5dc7dc0243d2 - std::panicking::try::do_call::h512c2ab2c15b7d31 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:557:40 37: 0x5dc7dc0243d2 - std::panicking::try::h5c2903f8937bc868 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:521:19 38: 0x5dc7dc0243d2 - std::panic::catch_unwind::h242c80217c2dbece at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panic.rs:350:14 39: 0x5dc7dc0243d2 - std::thread::Builder::spawn_unchecked_::{{closure}}::h6cb4494ebdd8caf7 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/thread/mod.rs:537:30 40: 0x5dc7dc0243d2 - core::ops::function::FnOnce::call_once{{vtable.shim}}::h42193b008049ba94 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/ops/function.rs:250:5 41: 0x5dc7dc08ebab - as core::ops::function::FnOnce>::call_once::ha1963004222e7822 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/alloc/src/boxed.rs:2070:9 42: 0x5dc7dc08ebab - as core::ops::function::FnOnce>::call_once::h1086ced1f7c494c2 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/alloc/src/boxed.rs:2070:9 43: 0x5dc7dc08ebab - std::sys::pal::unix::thread::Thread::new::thread_start::ha8af9c992ef0b208 at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/pal/unix/thread.rs:108:17 44: 0x768525b9039d - 45: 0x768525c1549c - 46: 0x0 - failures: tests::correct_coord_7 test result: FAILED. 17 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.03s error: test failed, to rerun pass `--lib` ```

workingjubilee commented 3 weeks ago

Floats are not reals, nor even decimals, they are binary numbers, so this is expected behavior. Sorry.

You can also reveal this quirk by writing

    assert_eq!(0.3_f64, 0.2 + 0.1);
theemathas commented 3 weeks ago

https://0.30000000000000004.com/

JeromeSchmied commented 3 weeks ago

thanks, than I suppose it's solved

but a quick question before closing, how can I test this kind of stuff?

theemathas commented 3 weeks ago

https://lib.rs/crates/float-cmp