5 ms·
> Do you know that in MSVC uint16_t(50000) + uin16_t(50000) == -1794967296? That problematic value is produced by multiplication (*), not addition (+). It happ
by nayuki 4y ago
> Do you know that in MSVC uint16_t(50000) + uin16_t(50000) == -1794967296?
That problematic value is produced by multiplication (*), not addition (+). It happens because uint16_t is unsigned short, and all arithmetic must be promoted to at least rank int.
The easiest universal fix for proper signed/unsigned arithmetic promotion is: (0U + uint16_t(50000)) * uint16_t(50000). See https://stackoverflow.com/questions/39964651/is-masking-before-unsigned-left-shift-in-c-c-too-paranoid https://stackoverflow.com/questions/39964651/is-masking-befo...
> And suddenly it turns out that all the “C++ killers”, even these which I wholeheartedly love and respect like Rust, Julia, and D, do not address the problem of the XXI century. They are still stuck in the XX.
You forgot to mention Carbon ( https://en.wikipedia.org/wiki/Carbon_(programming_language) https://en.wikipedia.org/wiki/Carbon_(programming_language) ) and cppfront ( https://github.com/hsutter/cppfront https://github.com/hsutter/cppfront ).
- rwbt 4y agoI think any reasonable C++ programmer should expect that adding two 16 bit uints of values 50000 will be greater than what a 16bit uint can hold and will overflow.
- Joker_vD 4y agoTo paraphrase Dijkstra, "the use of C++ cripples the mind; its teaching should, therefore, be regarded as a criminal offence". Maybe a reasonable C++ programmer would expect that, sure, but: should a reasonable programmer expect that? Automatic promotion to reasonably sized integers (and in the limit, integers of unlimited precision) is ancient tech.
- Koshkin 4y agoPlease do not put your own words in Dijkstra's mouth: he said exactly what needed to be said.
- otabdeveloper4 4y ago> just promote my arithmetic to bigints randomly, #YOLO
- Joker_vD 4y ago> Just throw away the most-significant digits randomly, #YOLO
- Koshkin 4y ago> any reasonable programmer FTFY
- Joker_vD 4y agoNo, it's exactly an unreasonable programmer who'd expect that, being conditioned to such ridiculous extravagancies by an inadequate language, which was the point of my another comment in this thread. Multiplication of intX_t by intX_t should produce int2X_t which is btw is what actually happens in hardware! And detection of overflow of addition/multiplication in a sane language should not require ridiculous algebraic acrobatics that involve additional additions/multiplications (or a division, yeah, I've seen that too).
- Koshkin 4y agoBut in a (typed) language, types are constraints that must be respected (regardless of what hardware does), and integer precision (as specified in code) is one of them.
- Joker_vD 4y agoSorry, what does "respect" means? Ruby and Pascal have division operator that takes two integers and returns a real — is this disrespectful? Is it disrespectful for multiplication to have signature template<size_t N> operator*(int<N>, int<N>) -> int<2*N> instead of template<size_t N> operator*(int<N>, int<N>) -> int<min(numeric_limits<int>::width, N)> ? Why or why not?
- Koshkin 4y agoTypes exist for a reason, and one is the desire for consistency (or uniformity) of representation: say, I want to be able to store the result of an operation in the storage element which looks the same as those where the operands came from (think of an array, for example).
- 4y ago
- deleted 4y ago[deleted]
- dannymi 4y agoActually, what will happen according to the C++ standard depends on the size of int. C++ is doing implicit integer promotion of integer variables with types smaller than int, and that promotion converts those values (of the operands of the +) to int (gross generalization yeah yeah). So the result on g++ amd64 will be 100000 (as you would expect) if int is more than 16 bits (nowadays it is), even WITH `(uint16_t(50000) + uint16_t(50000))`. I've also tried it in MSVC 2010 and it says the result of `std::cout << (uint16_t(50000) + uint16_t(50000)) << std::endl` is 100000 (both on win32 and on x64). Try it on an arduino and you will get 34464 (with g++ targeting 8 bit atmel). Think you want implicit integer promotion in a systems language? You really don't. They are an unnecessary language feature. Also, the article is only tangentially about that--that's just an intro. The actual body makes very good points, and I think it's more than a little tongue-in-cheek :)
- cynwoody 4y agoApparently, as the GP points out, the article author meant to write asterisk where he wrote plus. uint16(50_000) * uint16(50_000) is uint32(2_500_000_000), which turns out to be int32(-1_794_967_296), the garbage result the author cites.
- layer8 4y agoThat’s not the issue, though, because the operands are promoted to int, which in that example happens to be 32-bit. The actual issue is that the product 50000 * 50000 = 2500000000 exceeds even the 32-bit 2^32-1 = 2147483647 and due to modulo arithmetics results in 2500000000 - 2^32 = -1794967296. If int was 16-bit (which it is allowed to be), no integer promotion would take place, and the result would be 50000^2 mod 2^16 = 63744.