Rust:
fn main() {
let a: f32 = 1e7 + 0.5 + 0.5;
let b: f32 = 1e7f32 + 0.5f32 + 0.5f32;
println!("{}", a==c); // true
}
C: #include <stdio.h>
int main() {
float a = 1e7 + 0.5 + 0.5;
float b = 1e7f + 0.5f + 0.5f;
printf("%s\n", a==b ? "true" : "false"); // false
}
That's awesome. I'm totally fine with an annoying suffix like f32 if I never actually need to use it. While f might be a nicer suffice than f32, no suffix is even better. fn foo(x: f32) { println!("{}", x); }
fn main() {
let x = 5.0;
foo(x);
}
It will look at the signature for foo, and infer that x must be f32.Isn't this kind of inference dangerous? It seems that whichever call comes first is used to infer the type, so a single added line of code can change the type of a variable…
fn foo32(x: f32) { println!("{}", x); }
fn foo64(x: f64) { println!("{}", x); }
fn bar64() {
let x = 5.0; // f64
foo64(x);
foo32(x);
}
fn bar32() {
let x = 5.0; // f32, not f64
foo32(x);
foo64(x);
}Here's the compiler error that you'd get:
error[E0308]: mismatched types
--> src/main.rs:7:13
|
7 | foo32(x);
| ^ expected f32, found f64
error[E0308]: mismatched types
--> src/main.rs:13:13
|
13 | foo64(x);
| ^ expected f64, found f32 fn foo32(x: f32) { println!("{}", x); }
fn foo64(x: f64) { println!("{}", x); }
fn bar64() {
let x = 5.0; // f64
foo64(x);
foo32(x as f32);
}
fn bar32() {
let x = 5.0; // f32, not f64
foo32(x);
foo64(x as f64);
}Well, isn't float in C and C++ platform dependent, and just usually 4 bytes on common platforms? I like the idea of being explicit in the storage type, even if it's slightly more verbose.
In particular, everything but MSVC treats long as 64 bits, but MSVC treats it as 32 bits for backwards compatibility.
However, I haven't used int or long or long long in ten years or so. Thanks to stdint.h support finally making its way to all platforms, it's exclusively sized types like int32_t and uint16_t for me.
That means for the example you posted works is because the only valid operation that line of code can be resolved to as-is would be the case where all untyped values are inferred to be float by the inference engine.
Nope. `f32` is for single-precision floats, and `f64` is for double-precision floats. There have been some people lobbying for `f16` and `f128` as well.
Also, you don't need to use those suffixes. I imagine the OP is using them for maximum explicitness, but you can just write `1.0` and it will be inferred to a floating-point type as necessary (contrast `1`, which will be inferred to an integral type).
I used them because that's the style that was used inside of std::f32;
const INFINITY: f32 = 1.0 / 0.0;
totally works.