# \`TryFrom\` for \`f64\`

**URL:** <https://internals.rust-lang.org/t/tryfrom-for-f64/9793>\
**Category:** libs\
**Created:** [April 9, 2019, 8:42am UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793 "2019-04-09T08:42:02Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [April 22, 2019, 7:29pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/21 "2019-04-22T19:29:02Z")

</div>

That would work

---

<div class="post-metadata">

**Author:** ![DDOtten](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddotten/32/4334_2.png) [@DDOtten](https://internals.rust-lang.org/u/DDOtten)\
**Post date:** [April 22, 2019, 10:25pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/22 "2019-04-22T22:25:42Z")

</div>

We could also use `Result<f64,f64>` and return `Ok(value)` and `Err(nearest_value)` depending on whether the value is expressible exactly.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 23, 2019, 12:02am UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/23 "2019-04-23T00:02:43Z")

</div>

> [@ekuber](#):
>
> Would this be a reasonable behavior? (Only convert things that can be losslessly converted, otherwise fail)

I'm a fan of that definition of the semantics.

For float-\>int it might be good to temporarily have an extra check until [https://github.com/rust-lang/rust/issues/10184](https://github.com/rust-lang/rust/issues/10184) gets completely fixed...

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 23, 2019, 1:34pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/24 "2019-04-23T13:34:48Z")

</div>

This whole topic (and your post in particular) got me thinking about the floating point equivalent of real analysis, or I should, the lack of it. So far as I know there is no equivalent to real analysis (or complex analysis, or any other formal logic) over floating point numbers. Is there some equivalent? If there is, then the compiler could be upgraded with the rules for that formal analysis, which might allow it to do better code generation than it currently does (as well as find more bugs than it currently does).

---

<div class="post-metadata">

**Author:** ![eaglgenes101](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/eaglgenes101/32/4645_2.png) [@eaglgenes101](https://internals.rust-lang.org/u/eaglgenes101)\
**Post date:** [April 23, 2019, 3:18pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/25 "2019-04-23T15:18:52Z")

</div>

I think you’re looking for [numerical analysis](https://en.wikipedia.org/wiki/Numerical_analysis).

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [April 23, 2019, 3:34pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/26 "2019-04-23T15:34:42Z")

</div>

Specifically, a useful – albeit not well-known – approach to treating quantized/discretized numbers rigorously is [interval arithmetic](https://en.wikipedia.org/wiki/Interval_arithmetic).

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 23, 2019, 3:39pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/27 "2019-04-23T15:39:33Z")

</div>

I can’t tell, but does numerical analysis have the concept of `NaN`? The closest I ever came to figuring out how to handle it was to use rational numbers and treat `0/0` as `NaN`. Most of the rest of the stuff seemed to come out OK that way, but I never did a formal analysis, so I’m not sure if my logic is sound.

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 23, 2019, 3:43pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/28 "2019-04-23T15:43:56Z")

</div>

Thank you for that link! It could be useful as the basis for a formal logic of floating point numbers. I think that if we can merge them with the idea I mention earlier (`NaN` as `0/0`), then we might be able to reason over floating point numbers.

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [April 23, 2019, 5:06pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/29 "2019-04-23T17:06:07Z")

</div>

I’ve been thinking that the failure case could be something like

```rust
enum FloatConvertionError<Target> {
    NotRepresentable,
    Rounded(Target),
    Overflow,
    Underflow,
}

```

That should cover every case and also include the rounded value when possible.

---

<div class="post-metadata">

**Author:** ![DDOtten](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ddotten/32/4334_2.png) [@DDOtten](https://internals.rust-lang.org/u/DDOtten)\
**Post date:** [April 23, 2019, 5:13pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/30 "2019-04-23T17:13:54Z")

</div>

Underflow would be rounded to 0 right? So the error gives the nearest integer except when that integer is not in the range of the type. Maybe it would also be good to differentiate between NaN and infinity

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 23, 2019, 5:57pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/31 "2019-04-23T17:57:03Z")

</div>

What about `-0.0`? E.g.:

```rust
fn main() {
    let a: f64 = 0.0;
    let b: f64 = -0.0;
    let c: isize = 0;
    let d: isize = -0;
    println!("a = {:?}, b = {:?}, c = {:?}, d = {:?}", a, b, c, d);
    println!("a == b {:?}", a == b);
}

```

yields

```rust
a = 0.0, b = -0.0, c = 0, d = 0
a == b true

```

which suggests that there is no lossless conversion from `-0.0f64` to `0i64`.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [April 23, 2019, 6:38pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/32 "2019-04-23T18:38:55Z")

</div>

> [@ckaran](#):
>
> which suggests that there is no lossless conversion from `-0.0f64` to `0i64` .

Clearly it **cannot** be lossless, as the distinction between `+0.0f64` and `-0.0f64` has been lost.

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 23, 2019, 6:41pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/33 "2019-04-23T18:41:55Z")

</div>

So, is this considered to be an error or not?

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [April 23, 2019, 6:52pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/34 "2019-04-23T18:52:37Z")

</div>

It depends on the desired semantics of your computation. Interval arithmetic was invented to facilitate establishing bounds on the error in a computation. The IEEE Floating Point rounding modes were invented in part to facilitate interval arithmetic. In some computations, `-0.0` might be used to represent the interval `(-𝜖 .. 0.0]` in contrast to `+0.0` representing the interval `[0.0 .. +𝜖)` for minimally-representable `𝜖`.

---

<div class="post-metadata">

**Author:** ![ckaran](https://avatars.discourse-cdn.com/v4/letter/c/f475e1/32.png) [@ckaran](https://internals.rust-lang.org/u/ckaran)\
**Post date:** [April 23, 2019, 7:20pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/35 "2019-04-23T19:20:30Z")

</div>

Which means that we need to decide if this conversion should result in an error or not.

I personally feel that if any conversion is lossy in any way at all, then the `Err` variant should be returned, probably wrapping something like @ekuber’s `FloatConversionError`. We might store the ‘best’ value possible in the variant, or we might have several choices and let the end user decide what to do. E.g.:

```rust
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct RoundingChoices<Target> {
    upper: Target,
    lower: Target
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum FloatConversionError<Target> {
    NotRepresentable, // For NaNs
    NegativeZero, // -0.0f64
    Rounding(RoundingChoices<Target>),
    Overflow, // Greater than what the target type can represent
    Underflow // Less than what the target type can represent
}

```

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [April 23, 2019, 8:09pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/36 "2019-04-23T20:09:13Z")

</div>

The domain of values of information that is represented by binary floating-point numbers is almost always **approximate**. (Decimal floating-point numbers are sometimes used to represent currency, in which case those values are often **exact**.)

Aside from `NaN`s, floating point numbers can specify the point zero, a finite set of point values within non-zero positive and negative representable spans, and ±∞. They thus serve as a quasi-logarithmic representation of the field of real numbers, which intrinsically has both infinite span and infinite point density within any interval. Each floating-point value represents an infinite number of real values that are numerically closer (in some sense) to the specified floating-point value than to either the next-higher or next-lower values in the selected floating-point representation.

This viewpoint calls into question the conceptual simplification that an integer value can be the functional equivalent of a floating-point value. Stated differently, both integers and floating-point values represent small intervals of the infinite real line, where the integer intervals are equally spaced around zero and the floating-point intervals are quasi-exponentially spaced around zero. Conversion from floating-point to integer is a mapping of one type of interval to the other. The question then becomes, what mapping is best (i.e., most accurate). It is obvious that this depends on the measure of “best”, and one approach is unlikely to satisfy all requirements.

---

<div class="post-metadata">

**Author:** ![repax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/repax/32/1342_2.png) [@repax](https://internals.rust-lang.org/u/repax)\
**Post date:** [April 23, 2019, 9:22pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/37 "2019-04-23T21:22:13Z")

</div>

Since floating-point values are _all_ intervals, really, there is _no_ lossless way to convert any u64 to f64. Even

```rust
(1: u64) != (1.0: f64)

```

You might as well make a best-effort rounding. The rounding error will be larger as the magnitude increases. Pick a limit and fail beyond that.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 23, 2019, 9:35pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/38 "2019-04-23T21:35:12Z")

</div>

> [@Tom-Phinney](#):
>
> Clearly it **cannot** be lossless, as the distinction between `+0.0f64` and `-0.0f64` has been lost.

That said, `0.0 == -0.0`, so it depends on what one considers lossy.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [April 23, 2019, 11:27pm UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/39 "2019-04-23T23:27:20Z")

</div>

> [@scottmcm](#):
>
> That said, `0.0 == -0.0` , so it depends on what one considers lossy.

Precisely. That is the underlying problem with any finite-precision floating-point representation: what it means depends on how you want to use it. See [my earlier post in this thread](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/34) for an example where there is a semantic difference between `-0.0` and `+0.0`.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 24, 2019, 12:07am UTC](https://internals.rust-lang.org/t/tryfrom-for-f64/9793/40 "2019-04-24T00:07:36Z")

</div>

> [@Tom-Phinney](#):
>
> where there is a semantic difference

There certainly are, but note that even `Vec::clone` can generate something _equal_ that's still _distinguishable_, though -- the `capacity()` can be different, and the `as_ptr()` usually is.

[Previous page](https://internals.rust-lang.org/t/tryfrom-for-f64/9793.md?page=1)

[Next page](https://internals.rust-lang.org/t/tryfrom-for-f64/9793.md?page=3)
