[OT] The Usual Arithmetic Confusions

Ola Fosheim Grøstad ola.fosheim.grostad at gmail.com
Sun Jan 30 10:51:28 UTC 2022


On Saturday, 29 January 2022 at 12:23:28 UTC, Siarhei Siamashka 
wrote:
> performance disadvantages compared to `a[i]`. My guess is that 
> the D language design in this alternative reality would define 
> arrays indexing as a modular operation and consider the "memory 
> safety" goal perfectly achieved (no out of bounds accesses, 
> yay!).

Yes, the focus on memory safety is too narrow and can be counter 
productive.


> I'm not sure if I can fully agree with that. Correctness is a 
> major concern in C++.

It is a concern, but the driving force for switching from 
unsigned int to signed int appears to be more about enabling 
optimization. At least that is my impression.

Another issue is that having multiple integer types can lead to 
multiple instances of templates, which is kinda pointless.


> My understanding is that the primary source of unsigned types 
> in applications is (or at least used to be) the `size_t` type. 
> Which exists, because a memory buffer may technically span over 
> more than half of the address space, at least on a 32-bit 
> system.

Yes, *sizeof* returns *size_t* which is unsigned. I think that 
has more to do with history than practical programming.  But 
there is no reason for modern containers to return unsigned (or 
rather modular ints). Well, other than being consistent with STL, 
but not sure why that would be important.

>> This is something that D should fix!!
>
> Do you have a good suggestion?

How many programs rely on signed wrap-over? Probably none. You 
could just make a breaking change and provide a compiler flag for 
getting the old behaviour? Then another compiler flag for 
trapping on overflow.

> We lost this transparency a long time ago. Compilers are 
> allowed to optimize out big parts of expressions. Integer 
> divisions by a constant are replaced by multiplications and 
> shifts, etc. Functions are inlined, loops are unrolled and/or 
> vectorized.

But you can control most of those by hints in the source-code or 
compilation flags.

There is a big difference between optimizations that lead to 
faster code (or at least code with consistent performance) and 
code gen that leads to uneven performance. Sometimes hardware is 
bad at consistent performance too, like computations with float 
values near zero (denormal numbers), and that is very unpopular 
among realtime/audio-programmers. You don't want the compiler to 
add more such issues.


> Well, the reality is that this is not just a theoretical 
> discussion anymore. Trapping of arithmetic overflows already 
> exists in the existing programming languages. And programming 
> languages will keep evolving to handle it even better in the 
> future.

Yes, but trapping overflows have always existed in languages 
geared towards higher level programming. C and its descendants 
are the outliers.

It is true though that processor speed and branch-prediction has 
made it more attractive also for those that aim at lower level 
programming.

The best solution for a modern language is probably to:

1. Improve the type system so that the compiler more often can 
prove that overflow never can happen for an expression. This can 
also lead to better optimizations.

2. Make signed overflow checks the default, but provide an inline 
annotation to disable it.

I think in general that optimizing all code paths for performance 
is kinda pointless. Usually critical performance is limited to a 
smaller set of functions.




More information about the Digitalmars-d mailing list