# Poll: speed vs accuracy for \`Float64^-3\`

**URL:** <https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619>\
**Category:** Performance\
**Tags:** poll, math, float\
**Created:** [March 9, 2022, 7:31am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619 "2022-03-09T07:31:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [March 9, 2022, 7:31am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/1 "2022-03-09T07:31:11Z")

</div>

In Julia 1.8, we are getting a pure Julia `pow` function, and as discussed in [https://github.com/JuliaLang/julia/pull/44529](https://github.com/JuliaLang/julia/pull/44529), part of this involved fixing a bug in `x^-3`.  
Before 1.8, Julia’s Literal pow meant that `10^-3 = 0.0010000000000000002` even though `10.0^-3 = .001`. Since literal pow is supposed to always return the same result as `^`, this is a bug that we needed to fix for 1.8

There are 2 possible meanings for `x^-3`. The first is `inv(x)*inv(x)*inv(x)`. The second is to return the floating point value closest to `big(x)^-3`. The first is about 3x faster, (about 2ns compared to 6ns), but is slightly less accurate. For example, the first approach returns `0010000000000000002` for `10^-3`, while the second returns `.001`. Given this, which would you prefer?

_Poll ([view on site](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/1))_

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [March 9, 2022, 7:32am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/2 "2022-03-09T07:32:44Z")

</div>

Note that the decision only affects exponents of `-3`. All others have a clearly correct choice.

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [March 9, 2022, 7:48am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/3 "2022-03-09T07:48:54Z")

</div>

I don’t think I have a considered view as this is unlikely to ever going to matter for me, but is there some guiding principle to follow? One example would be integer overflow, where speed is chosen over security (leading to tons of newbie complaints) on the basis that people can always opt in to the “safe”/“correct” behaviour explicitly.

This would favour the `inv` approach here, with users opting for `big` where needed explicitly. Of course this tradeoff will always depend on how “bad” the inaccuracy is vs. how big the speed hit is, so maybe the relative cost/benefit here is very different than for integer overflow.

---

<div class="post-metadata">

**Author:** ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)\
**Post date:** [March 9, 2022, 7:54am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/4 "2022-03-09T07:54:38Z")

</div>

Floating-point arithmetic should not use `BigFloat`s (i.e. MPFR) internally. In addition to that being a quite clunky solution, it potentially opens up some problems with thread safety

[https://docs.julialang.org/en/v1/base/numbers/#Base.Rounding.setrounding-Tuple{Type,%20Any}](https://docs.julialang.org/en/v1/base/numbers/#Base.Rounding.setrounding-Tuple%7BType,%20Any%7D)

Why isn’t falling back to floating-point `pow` on the table? If we want the same results maybe we should just run the same method.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [March 9, 2022, 8:12am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/5 "2022-03-09T08:12:12Z")

</div>

I think you misunderstand the role of `BigFloat` in this context. The question is whether to match the _result_ of a `BigFloat` computation, not to perform any computations with `BigFloat`. Had the latter been an option we wouldn’t be discussing 2ns versus 6ns.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 9, 2022, 8:42am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/6 "2022-03-09T08:42:51Z")

</div>

So is this the current behaviour?

```julia
1.7.2> foo(x) = x^(-3)
foo (generic function with 1 method)

1.7.2> @btime foo(x) setup=(x=10rand())
  63.432 ns (0 allocations: 0 bytes)

```

So, we are talking about _either_ fixing an inaccuracy and getting a 10x speedup, _or_ not fixing the inaccuracy and getting a 30x speedup?

I think that by choosing the first alternative, we actually have it both ways. If you need to squeeze out the last nanoseconds, you would just do `1/x^3` instead of `x^(-3)`.

Based on this: Definitely alternative 2.

You should actually call the alternatives:

- More accurate and much faster than now.
- Same inaccuracy as before but even faster.  
(Note, I changed the order of the alternatives, for language reasons.)

---

<div class="post-metadata">

**Author:** ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)\
**Post date:** [March 9, 2022, 8:44am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/7 "2022-03-09T08:44:53Z")

</div>

Thanks you for explaining. In that case, I don’t even understand the question. The result should be as accurate as possible (unless I use something like `@fastmath`)

---

<div class="post-metadata">

**Author:** ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)\
**Post date:** [March 9, 2022, 8:49am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/8 "2022-03-09T08:49:10Z")

</div>

I’m fairly certain [IEEE 754 - Wikipedia](https://en.wikipedia.org/wiki/IEEE_754) has something to say on the question. The `Base` mathematics should be IEEE compliant…

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 9, 2022, 8:52am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/9 "2022-03-09T08:52:33Z")

</div>

I’m not sure if IEEE 754 covers powers. The wikipedia page only lists

> - Arithmetic operations (add, subtract, multiply, divide, square root, [fused multiply–add](https://en.wikipedia.org/wiki/Multiply%E2%80%93accumulate_operation), remainder)

so there may be some leeway.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [March 9, 2022, 9:27am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/10 "2022-03-09T09:27:02Z")

</div>

This would also be a great opportunity to decide this in general for all of Base and the standard libraries, at least at the level of a “soft” requirement that we don’t deviate from unless there is a really compelling reason.

Practically, I would suggest always going for the more accurate implementation unless the alternative is significantly faster. Eg for me to give up 4\varepsilon of precision, I would expect at least a 20x performance increase. (Of course I just made these numbers up, share your own preferences).

---

<div class="post-metadata">

**Author:** ![FrancisKing](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francisking/32/24966_2.png) [@FrancisKing](https://discourse.julialang.org/u/FrancisKing)\
**Post date:** [March 9, 2022, 9:27am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/11 "2022-03-09T09:27:55Z")

</div>

As a user, I would like to always have a choice.

---

<div class="post-metadata">

**Author:** ![lawless-m](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lawless-m/32/30869_2.png) [@lawless-m](https://discourse.julialang.org/u/lawless-m)\
**Post date:** [March 9, 2022, 9:41am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/12 "2022-03-09T09:41:58Z")

</div>

I voted for accurate on the basis that inaccuracy for speed should be opt-in. Which, of course, contradicts using Float64 but lets not get into that 🙂 .

Although, tbh, it seems to be rather insignificant for my work

---

<div class="post-metadata">

**Author:** ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)\
**Post date:** [March 9, 2022, 9:51am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/13 "2022-03-09T09:51:09Z")

</div>

> [@DNF](#):
>
> you would just do `1/x^3` instead of `x^(-3)`

You may easily get an overflow in this case (especially if x is `Int`). I think if `inv(x)*inv(x)*inv(x)` is guaranteed to be within 1 ulp in most cases, then the faster option will be better. In other cases where accuracy is the most important, one can opt for `big()` and friends, or check their algorithm for numerical stability/sensitivity.

---

<div class="post-metadata">

**Author:** ![t-bltg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/t-bltg/32/25526_2.png) [@t-bltg](https://discourse.julialang.org/u/t-bltg)\
**Post date:** [March 9, 2022, 9:52am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/14 "2022-03-09T09:52:05Z")

</div>

@DNF has a point: if it isn’t slower than before, we should prefer accuracy.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 9, 2022, 10:06am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/15 "2022-03-09T10:06:50Z")

</div>

754-2019:

> Language standards should define, to be implemented according to this subclause, as many of the operations in Table 9.1 as is appropriate to the language. As with other operations of this standard, the names of the operations in Table 9.1 do not necessarily correspond to the names that any particular programming language would use. In this subclause the domain of an operation is that subset of the affinely extended reals for which the corresponding mathematical function is well defined. A conforming operation shall return results correctly rounded for the applicable rounding direction for all operands in its domain.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/1/11f1a1332f16b1c0bc40713bb2c8fac3ffb940db.png)

```julia
# Numba
In [23]: @njit
    ...: def f(x): return x ** -3
In [24]: f(10.0)
Out[24]: 0.001

# Rust
println!("{}", 10.0_f64.powi(-3));
0.001

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 9, 2022, 10:12am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/16 "2022-03-09T10:12:31Z")

</div>

> [@Seif\_Shebl](#):
>
> You may easily get an overflow in this case (especially if x is `Int` ).

Or `(1/x)^3`, it was just an example.

> [@Seif\_Shebl](#):
>
> In other cases where accuracy is the most important, one can opt for `big()` and friends, or check their algorithm for numerical stability/sensitivity.

Going a tiny extra step to get more performance over accuracy is reasonable. Having to use `big` to get accuracy is _way_ over the top, imho, not to mention that it’s \>100x slower than the “‘slow’ but accurate” alternative.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 9, 2022, 10:17am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/17 "2022-03-09T10:17:33Z")

</div>

Actually, how _would_ you get the accurate version, if we go for the ‘fast path’?

It seems that if we go the ‘slow’ path, then trading performance and accuracy will be easy, and fast either way.

If we go the ‘fast path’, how easy is it to trade off accuracy and speed?

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [March 9, 2022, 10:53am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/18 "2022-03-09T10:53:54Z")

</div>

The false dichotomy in the poll should be corrected. please make a correct poll instead, if needed with implementation details. The `big(...)` is misleading.

---

<div class="post-metadata">

**Author:** ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)\
**Post date:** [March 9, 2022, 11:22am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/19 "2022-03-09T11:22:16Z")

</div>

The Julia `Float64` type is already defined as an IEEE 754 number. So question cannot be to deviate from the standard, rather the question is: How strict is the standard w.r.t. this operation (`x¯³`)?

[https://docs.julialang.org/en/v1/base/numbers/#Core.Float64](https://docs.julialang.org/en/v1/base/numbers/#Core.Float64)

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 9, 2022, 11:45am UTC](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619/20 "2022-03-09T11:45:53Z")

</div>

> [@Oscar\_Smith](#):
>
> Since literal pow is supposed to always return the same result as `^`

Fortran, Octave, and Python, as far as I tested, all return exactly `0.001` for `10.0^(-3)`, thus I guess it wouldn’t be very nice if Julia returned something different for that floating point operation, in which case the literal power should return that as well.

[Next page](https://discourse.julialang.org/t/poll-speed-vs-accuracy-for-float64-3/77619.md?page=2)
