Closed Oleg-N-Cher closed 8 years ago
The arithmetic shift is implemented with the same logic as in GPCP
ASH is arranged in different ways in different implementations of Oberon. For example, in BlackBox ASH (x, n) - n can be any integer including LONGINT. I see it as excessive. What a long type to do for n? In GPCP n is an INTEGER type, and that is correct - make a person more cautious when the long variable or expression used n, think about SHORTH( ), etc. While the SHORT( ) there may has a side effect (for n like SHORT(100000001H) => 1 ) in runtime gives a small number for the shift ( 1 ), and that's the wrong result. Not 0, as after the shift to ultra-large number, but it is shifted to a low value ( 1 ). I agree, this case looks rare, but it still can happen, and it's a dangerous.
This is done not only to focus attention on the fact that n can be LONGINT, and we have not noticed, but also for efficiency - do not use too long number where it is not really required.
So I find GPCP's implementation of ASH the most perfect.
P.S. As it turned out, shift operations << and >> in С language, as signed (arithmetic shift), as unsigned (logical shitf), have a specific implementation: the result is not defined, if ABS(n) >= the number of bits to be shifted. GPCP returns 0 in this case. It looks more clean and perfect, but less effective for existing processor architectures (like i80x86).
• https://github.com/Oleg-N-Cher/OfrontPlus/commit/8dd600c58ace88e8d902991cd930114f01eb0c3d • https://github.com/Oleg-N-Cher/OfrontPlus/commit/f31bed70490b91fb24dad9bf1b1dcafd34916043 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/6a2dc15a9fbee8b9fc4e9563a565dc259c86ae57 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/4f34598a82533b439179c3fafd36e5348b66e940 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/fbaa2ea58a17df8064562b94ccda32c62fb5fa83 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/891fb51b27adab9211dd08db832aa14183fb9756 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/ae2687ff15ecdf43b9fad64e6bf1a91de5cd7183 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/6d60c073f6d3a01e41bf42a0ef51d121d38fe8c9 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/76385c8beae937a185e91377c11bc236120bc5fe • https://github.com/Oleg-N-Cher/OfrontPlus/commit/fb7f9ff916c75fdfaec008ca954559e1cd774ca3 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/c6cb9f41145804a6571cc4541408111fc6081b11 • https://github.com/Oleg-N-Cher/OfrontPlus/commit/be85d867025d042637ee07fce8133088b9013667
In SYSTEM.h we see:
As we know, type "long long" is always 64 bit, while "long" may be 32 bit e.g. under MS Visual C/MinGW. So to adapt ASHL, ASHR for 64 bit, we can use cast to "long long", but isn't it overhead?
Ofront's docu:
Result is always LONGINT, but keep in mind the fact that type LONGINT previously cannot be 8 bytes in Ofront - we just now adapt it to this size.
Take look to BlackBox:
GPCP:
As we know, constants have an implicit type in Ofront:
So if we need LONGINT result for ASH, we can call ASH(LONG(argument)) or even ASH(LONG(LONG(argument))). As we see, LONGINT result by default for INTEGER argument is not so good idea as I thought at first.
So I suggest this way:
Thus, the advantage of my proposal is no overhead (while cast INTEGER argument to LONGINT and result from LONGINT to INTEGER back), and also compatibility with BlackBox and GPCP. Because the result of multiplication of two INTEGERs can always be LONGINT too, and so on. And it is normal practice in the care of very large numbers where they are excessive.