To add integer and float numbers together, I understood, there are 2 options, either `casting` or `impl trait`.

For `casting` I used the below code that worked fine:

``````let x = 1;
let y = x as f32 + 3.0;
``````

If I removed the `as f32` casting, I get the below error:

The trait `std::ops::Add<{float}>` is not implemented for `{integer}`

How can I do this implementation? It's not possible for you to implement external traits (like `Add`) for external types (like floats and integers). This case could only be added directly in the standard library, specifically in `core`.

But Rust generally discourages mixing types in arithmetic. In C and C++, there are type promotion rules that let this work implicitly, but Rust wants you to be explicit about such type conversions.

6 Likes

Rust has u32 and double, you can add together like this:

``````fn main() {
let n: u32 = 15;
let x: f64 = 6.5;
let result = x + f64::from(n);
}
``````
2 Likes

The auto conversion of type is dangerous sometime. Here is a simple C example:

``````#include <stdio.h>

int main() {
const float bw = 1./3.;

int d1 = (int) (4./bw);
int d2 = (int) (4 /bw);
printf("4/(1/3) is: %d or %d ??\n", d1, d2);

return 0;
}
``````

4/(1/3) is: 11 or 12 ??

5 Likes

How the 11 poped up, it should be 12 only¡¡

First, remember that `1./3` can't be perfectly represented in a `float`. GDB tells me that `bw` is rounded up slightly to `0.333333343`. So when we divide "4" by `bw`, we should actually expect to get something slightly less than 12.

http://c0x.coding-guidelines.com/6.3.1.8.html

First, if the corresponding real type of either operand is long double, the other operand is converted, without change of type domain, to a type whose corresponding real type is long double.

Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose corresponding real type is double.

Otherwise, if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose corresponding real type is float.

In computing `d1`, the literal `4.` is a `double`, so `bw` is converted to `double` for the division. This computes `11.999999642372142`, which is then truncated by `(int)` to `11`.

In computing `d2`, the literal `4` is an `int`, so that is converted to `float` to match `bw`. Since this has less precision, it rounds up to exactly `12.0000...` -- and then `(int)` gives `12` as well.

2 Likes

I found this type-autoconversion rounding bug in a C software on GitHUB, and I made the simple example. In Rust the type-conversions are explicit, not automatic.

``````fn main() {
let bw: f32 = 1./3.;

let d1: i32 = (4./bw) as i32;
let d2: i32 = (4 as f32/bw) as i32;
println!("4/(1/3) --> both are 12: {} {}", d1, d2);
}
``````

Since of this C-bug, I don't like the automatic type conversion, if the good result is important.

1 Like

I wouldn't actually call this example a C bug, per se, but more of a general issue of expecting too much accuracy from floating point. It's just that C's promotion rules tend to hide the actual types used for a given computation.

The Rust equivalent to C's type promotions would be this, which also gives you 11:

``````    let d1: i32 = (4. / bw as f64) as i32;
``````

Note that Rust lets the type of `4.` be inferred by context, either `f32` or `f64`, whereas it's always a `double` in C.

While this computation in `f32` and `float` gives the exact result you want, it's somewhat lucky that imprecise floating point rounded that way. If you try with `1./7.`, you'll get `27` in both cases.

3 Likes

My advice would be: don't use floats.

Except for numerical software, stuff like games etc. and other minor exceptions, floats should probably never be used for anything.

Use integers instead. Decide on the precision you want and go with that.

3 Likes

Thanks.
In this `C` code it looks `1./3` will be rounded correctly if defined `double`, so as @dpc mentioned, beter to avoid using `float`.

By "float" I believe he was referring to floating-point types in general. So both `float` and `double`. All floating-point types lose precision and will result in weird bugs like this when you convert them to integers. The problem is just less pronounced with double since it has higher precision.

4 Likes

On the topic of floating point precision, there are also crates (and C libraries) that implement arbitrary precision arithmetic.

A few examples, num in pure Rust and gmp which provides bindings to gmplib. Use one of these libraries if you need accurate arithmetic results. Floating point numbers are good for approximations.

3 Likes