4 ms·
> In the concrete version, the code says that every Zero in the arguments should be un-vanished into 0.0 before doing the calculation; I am assuming that the ge
by MauranKilom 6y ago
> In the concrete version, the code says that every Zero in the arguments should be un-vanished into 0.0 before doing the calculation; I am assuming that the generic multiply will be monomorphized, the concrete result expressions will be inlined, and constant propagation will turn expressions involving the Zero arguments back into no-ops.
Did you actually test whether this happens? If I understand correctly, you want to rely on the optimizer constant-folding multiplications with zero to zero. But strict IEEE floating point conformance notoriously does not allow collapsing multiplication with zero to zero (consider NaNs and infinities), or addition of zero to be a no-op (consider signed zeros).
Example:
https://godbolt.org/z/cGv17o https://godbolt.org/z/cGv17o
That also affects the overall goal, seeing as the type-level optimizations do assume the above properties. This means that you will get different results in certain edge cases than a "naive" implementation that always stores 16 floating point values for each multivector (and that's before getting to things like non-associativity of floating point operations).
- fanf2 6y agoOoh thanks that’s horrible :-) Yes I need to investigate that in more detail. Edited to add: one option for making my assumption true might be to use fmul_fast and friends https://doc.rust-lang.org/core/intrinsics/fn.fmul_fast.html https://doc.rust-lang.org/core/intrinsics/fn.fmul_fast.html
- frazar0 6y agoAn alternative could be to create another zero-sized type for NaN and Infinity
- fanf2 6y agoYeah I have been thinking about something like that, but we don’t know at compile time when NaN will turn up. (I suppose if you take abstract interpretation as far as you can, you get to partial evaluation, but I am not in that game!) 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.
- BoiledCabbage 6y agoIt's incredible the "right" response to OPs comment isn't "for all the great benefits we've had, we've also really f'ed up programing along the way". Instead it's "yes it's my fault that I forgot about the nonsensical concepts of positive and negative zero, and that the associative operation of addition isn't actually associative, and that addition's identity isn't actually and identity..." Scheme has Numerical towers that automatically abstract over exact numeric representations, but instead this clearly smart engine is forced to spend mental cycles remembering and debugging this arbitrary special case logic. Nulls, floating point, ... we really have some huge programming mistakes that have cost so much time over the years. An no this isn't a rant on 'everybody should use scheme or Lisp, because that completely misses the point. It's that 'Worse Is Better' really is worse in the long run.