Unexpected value when constructing a scaled_integer from a literal integer (with Radix != 2)
Describe the bug:
I think this piece of code describes it pretty well:
https://godbolt.org/z/T5jPqKa9n
When initializing a radix 10 scaled_integer from a integer literal, I get the wrong value. The issue doesn't seem to happen if radix is 2. Initializing from a double literal seems find on any radix.
Hi,
Thanks for checking out CNL.
The issue you are seeing is because to represent the number you're entering involves multiplying the input (a 32-bit integer) by 9^10 (5 * 1'000'000'000) which is outside the range of that integer type. Passing in 5L instead of 5 is the quickest way to ensure the input type is wide enough to scale that far.
The scaled_integer type is only concerned with scaling, but does not address overflow, and nor do fundamental integers (though I'm disappointed that ASan cannot trap this overflow). You can use scaled_integer to ensure that such errors don't go unnoticed:
// traps overflow at run-time, rather than allowing a wrong value cnl::scaled_integer<cnl::overflow_integerstd::int64_t, cnl::power<-9, 10>> v{5}
I agree it isn't ergonomic for overflow to happen so easily.
See the FAQ section on overflow, and answers to #896, #652, and #576 for more information.
I'm keeping this open until such time as it gets added as a unit test, and the UX gets improved. Questions to answer:
- Why don't literals help, e.g.
5_cnl? - Why doesn't ASan trap this?
Hi,
Thanks for the detailed response. That makes sense. I kinda wish that the scaled_integer ctor would cast the input to the Rep type before the multiplication, so this overflow would be avoided. But, except for float inpupts, of course. I'm sure there are other considerations to be made, but I might just have a local patch for CNL to change that behavior locally. I considered writing a wrapper around CNL, but that actually takes a little too much code. In any case, thanks for writing CNL!
Cheers
No problem. You're welcome. I've certainly thought about that sort of solution but ultimately, it's a Hard Problem(tm). What if the power was, say, <-90, 10>? There's no fixing that with a wider built-in integer! Meanwhile, working code would be pessemized elsewhere. Good luck with your numeric adventures!