An alternative could be to create another zero-sized type for NaN and Infinity
Another idea is to rely on Rust-specific optimizations: make the concrete type used by the result expressions into
enum ZeroNum {
Zero,
Num(f64),
}
Operator overloading on this type works like it does on the separate Zero and Num types, but the cases are tested at run time instead of compile time. But this type is only used in a small context where the optimizer should be able to eliminate the checks in the same way I naively thought it would do for ops with 0.0.