[Bug algol68/126062] New: ga68 mishandles negative integer
chris hermansen
clhermansen@gmail.com
Tue Jul 7 04:38:49 GMT 2026
A few further comments at the very end.
On Mon, Jul 6, 2026 at 3:47 PM chris hermansen <clhermansen@gmail.com>
wrote:
> Good afternoon, all;
>
> Please see my comments at the end.
>
> On Wed, Jul 1, 2026 at 2:24 AM jemarch at gcc dot gnu.org <
> gcc-bugzilla@gcc.gnu.org> wrote:
>
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126062
>>
>> Bug ID: 126062
>> Summary: ga68 mishandles negative integer
>> Product: gcc
>> Version: 16.0
>> Status: UNCONFIRMED
>> Severity: normal
>> Priority: P3
>> Component: algol68
>> Assignee: algol68 at gcc dot gnu.org
>> Reporter: jemarch at gcc dot gnu.org
>> Target Milestone: ---
>>
>> [Reported by Nelson H. F. Beebe]
>>
>> Consider these two programs for printing integers near the 32-bit
>> integer overflow limit:
>>
>> % cat bigint32.c
>> #include <stdint.h>
>> #include <stdio.h>
>> #include <stdlib.h>
>>
>> int
>> main(void)
>> {
>> int32_t k, m;
>>
>> m = 2147483647;
>> (void)printf(" m = %11d\n", m);
>>
>> for (k = 0; k <= 5; ++k)
>> (void)printf("-m - %d = %11d\n", k, (-m) - k);
>>
>> return (EXIT_SUCCESS);
>> }
>>
>> % cat bigint.a68
>> begin
>> int m = 2147483647;
>> int k;
>> puts(" m = " + whole(m, 11) + "'n");
>> for k from 0 to 6
>> do
>> puts("-m - " + whole(k, 0) + " = " + whole(-m - k, 11) + "'n")
>> od
>> end
>>
>> The first when run produces the expected output from undetected signed
>> integer overflow in two's complement arithmetic (universal today):
>>
>> % cc bigint32.c && ./a.out
>> m = 2147483647
>> -m - 0 = -2147483647
>> -m - 1 = -2147483648
>> -m - 2 = 2147483647
>> -m - 3 = 2147483646
>> -m - 4 = 2147483645
>> -m - 5 = 2147483644
>>
>> Now see what the Algol 68 version produces:
>>
>> % ga68 --version
>> ga68 (GCC) 17.0.0 20260426 (experimental)
>> ...
>>
>> % ga68 bigint.a68 && ./a.out
>> m = +2147483647
>> -m - 0 = -2147483647
>> -m - 1 = -8963627462
>> -m - 2 = +2147483647
>> -m - 3 = +2147483646
>> -m - 4 = +2147483645
>> -m - 5 = +2147483644
>> -m - 6 = +2147483643
>>
>> The value for -m - 1 should be the most negative integer, -2147483648,
>> but instead, the value -8963627462 (== -0x2164619c6) appears.
>>
>> This seems like a definite bug in the ga68 transput code, or in the
>> whole() conversion function!
>>
>> A version for the Algol 68 Genie compiler works like the C version:
>>
>> % cat bigint.a68
>> BEGIN
>> INT m = 2147483647;
>> INT k;
>> print((" m = ", whole(m, 11), newline));
>> FOR k FROM 0 TO 6
>> DO
>> print(("-m - ", whole(k, 0), " = ", whole(-m - k, 11), newline))
>> OD
>> END
>>
>> % a68g bigint.a68
>> m = +2147483647
>> -m - 0 = -2147483647
>> -m - 1 = -2147483648
>> -m - 2 = -2147483649
>> -m - 3 = -2147483650
>> -m - 4 = -2147483651
>> -m - 5 = -2147483652
>> -m - 6 = -2147483653
>>
>> --
>> You are receiving this mail because:
>> You are the assignee for the bug.
>
>
> Looking at the above, I don't understand the comment "A version for the
> Algol 68 Genie compiler works like the C version"
>
> The Genie numbers from -m - 2 on down are negative (remember Genie uses 64
> bit integers).
>
> The GNU Algol 68 numbers, except for -m - 1, match the C numbers.
>
> Or am I missing something?
>
> Anyway, since I have van Vliet's partial implementation cracked open on
> the bench, I thought I would try his whole and subwhole routines to see if
> they produce the correct results...
>
> And unfortunately, they mess up on the -m - 1 value as well.
>
> m = +2147483647
> -m - 0 = -2147483647
> -m - 1 = -8963627462
> -m - 2 = +2147483647
> -m - 3 = +2147483646
> -m - 4 = +2147483645
> -m - 5 = +2147483644
> -m - 6 = +2147483643
>
> I wonder if the problem here is that both RR and van Vliet converters
> take the ABS of the argument. If we add a bit to Nelson's program as:
>
> begin
> int m = 2147483647;
> int k;
> puts(" m = " + whole(m, 11) + "'n");
> for k from 0 to 6
> do
> puts("-m - " + whole(k, 0) + " = " + whole(-m - k, 11) + "'n")
> od;
> puts("ABS m = " + whole(ABS m, 11) + "'n");
> for k from 0 to 6
> do
> puts("ABS (-m - " + whole(k, 0) + ") = " + whole(ABS (-m - k), 11)
> + "'n")
> od
> end
>
> and run this, we get:
>
> m = +2147483647
> -m - 0 = -2147483647
> -m - 1 = -8963627462
> -m - 2 = +2147483647
> -m - 3 = +2147483646
> -m - 4 = +2147483645
> -m - 5 = +2147483644
> -m - 6 = +2147483643
> ABS m = +2147483647
> ABS (-m - 0) = +2147483647
> ABS (-m - 1) = -8963627462
> ABS (-m - 2) = +2147483647
> ABS (-m - 3) = +2147483646
> ABS (-m - 4) = +2147483645
> ABS (-m - 5) = +2147483644
> ABS (-m - 6) = +2147483643
>
> Not sure if this sheds any light on things...
>
> Ruminating on this a bit more...
I don't like the "two integer divisions" approach advocated in the RR and
in van Vliet. A nice alternative is:
1. maintain a table of powers of 10 [1,10,100,1000 etc]
2. maintain a procedure or operator that uses an if-then-elif... fi to
look up the number of digits in the argument
Then a procedure that looks something like this:
proc tos_format_integer = (union (
{iter L {long long } {long } {} {short } {short short }}
{L}int
{reti {,}}
) number, bool always_show_sign) string:
begin
char char_null = REPR 0;
int char_zero = ABS "0";
char sign_char;
int chars_needed;
int number_digits = DIGITS number;
int result_char;
case number in
{iter L {long long } {long } {} {short } {short short }}
{iter K {LENG LENG } {LENG } {} {SHORTEN } {SHORTEN SHORTEN }}
{iter S {SHORTEN SHORTEN } {SHORTEN } {} {LENG } {LENG LENG }}k
{iter T {} {SHORTEN } {SHORTEN SHORTEN } {SHORTEN SHORTEN SHORTEN }
{SHORTEN SHORTEN SHORTEN SHORTEN }}
({L}int number_to_convert):
begin
{L}int work := number_to_convert;
if number_to_convert < {L}0
then
sign_char := "-";
chars_needed := number_digits + 1
elif number_to_convert > {L}0 always_show_sign then
sign_char := "+";
chars_needed := number_digits + 1
else
sign_char := char_null;
chars_needed := number_digits
fi;
[1:chars_needed]char result;
result_char := (sign_char /= char_null | result[1] := sign_char; 2 | 1);
for digit_number from number_digits by -1 to 1 do
{L}int p10 = {T}powers_of_10[digit_number];
int digit = {S} (work % p10);
result[result_char] := REPR (ABS digit + char_zero);
result_char +:= 1;
work -:= {K}digit * p10
od;
result
end
{reti {,}}
esac
end { tos_format_integer };
NB there is a bit "left to the reader" above and I haven't tested it in
this extracted version...
If anyone cares for more detail, I have this in a slightly more expanded
form, that permits localization and separators. Happy to share. I've
recently tuned it up to use sppp.awk but haven't got around to beating on
my old floating point stuff.
--
Chris Hermansen · clhermansen "at" gmail "dot" com
C'est ma façon de parler.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/algol68/attachments/20260706/b9ca5584/attachment.htm>
More information about the Algol68
mailing list