Integer-to-string conversion error solved
chris hermansen
clhermansen@gmail.com
Sat Jul 11 00:16:12 GMT 2026
Good afternoon all,
On Fri, Jul 10, 2026 at 12:49 AM Jose E. Marchesi <jemarch@gnu.org> wrote:
>
> > Good afternoon everyone,
> >
> > On Thu, Jul 9, 2026 at 12:34 PM Jose E. Marchesi <jemarch@gnu.org>
> wrote:
> >
> >>
> >> > Good morning, all;
> >> >
> >> > On Thu, Jul 9, 2026 at 9:51 AM Jose E. Marchesi <jemarch@gnu.org>
> wrote:
> >> >
> >> >>
> >> >> > Thanks, Jose, for the quick response about the current incorrect
> >> >> > string conversions of the most negative integers.
> >> >> >
> >> >> > No, I am certainly not suggesting that ga68 change the
> implementation
> >> >> > of the Algol 68 MOD operator, which is language defined and must be
> >> >> > standard.
> >> >> >
> >> >> > It is the USE of MOD in integer-to-string conversions that
> produces an
> >> >> > incorrect string for -(2**(n - 1)), so it is just the conversion
> >> >> > routines that need repair.
> >> >>
> >> >> Yes that's what I was asking. In our current transput implementation
> >> >> that would be 'subwhole'.
> >> >>
> >> >> I will incorporate your fix in our current transput.
> >> >>
> >> >> Note that Chris Hermansen is working on our new full-fledged
> transput,
> >> >> based on van Vliet's, which might or might not provide a new
> >> >> implementation of `whole'. In that case, and if the new
> implementation
> >> >> uses MOD, we will be careful to use your version so we are compatible
> >> >> with C number printers.
> >> >>
> >> >> > Algol 68 parses integers without a sign, and then only afterwards
> >> >> > applies unary signs. That is why, as in many programming
> languages,
> >> >> > there are subterfuges like the C header file, <limits.h>, with code
> >> >> > like this:
> >> >> >
> >> >> > #define INT_MAX 2147483647
> >> >> > #define INT_MIN (-INT_MAX - 1)
> >> >> >
> >> >> > A human programmer unfamiliar with details of hardware arithmetic
> may
> >> >> > well wonder, and complain about, the refusal of the compiler to
> accept
> >> >> > the constant -2147483648. My view has always been that compilers
> >> >> > SHOULD accept such constants: all that is needed is digit
> accumulation
> >> >> > as a negative value, then attaching the sign after all the digits
> have
> >> >> > been collected: grammar rules, alas, may prevent that helpful
> >> >> > practice.
> >> >>
> >> >> We actually take care in our implementation to support using
> -2147483647
> >> >> (and similar to other type widths) as an integral denotation:
> >> >>
> >> >> if (errno == ERANGE
> >> >> || (NEGATED (p) && (val > max_negative))
> >> >> || (!NEGATED (p) && (val > max_positive)))
> >> >> {
> >> >> a68_moid_format_token m (moid);
> >> >> a68_error (s, "denotation is too large for %e", &m);
> >> >> }
> >> >>
> >> >> Note the NEGATED attribute which is stored in the AST node
> corresponding
> >> >> to the integral denotation. That is only set if the integral
> denotation
> >> >> is immediately passed to the unary minus operator.
> >> >>
> >> >> > Two's complement arithmetic is essentially universal today: the CDC
> >> >> > 6x00/7x00 and Univac 11xx systems of the 1960s and 1970s were the
> last
> >> >> > major CPUs that (I can recall at the moment) had the symmetric
> one's
> >> >> > complement arithmetic, for which INT_MIN = -INT_MAX, but then also
> >> >> > there is +0 and -0, which complicates comparisons.
> >> >> >
> >> >> > My concern is that output of all possible integers as strings, and
> >> >> > subsequent conversion of those strings back to integers, MUST be
> >> >> > round-trip correct for all possible numbers.
> >> >>
> >> >
> >> > I have a standalone proposed alternative to whole (and subwhole) that
> at
> >> > least solves the incorrect largest negative problem. I would like to
> >> offer
> >> > it up here for general inspection, evaluation etc before formally
> >> proposing
> >> > it.
> >> >
> >> > Also, running it over integers from -1 000 000 to +1 000 000 and
> sending
> >> > the output to /dev/null, it completes in 1.184s on my desktop, whereas
> >> > using the old whole completes in 2.677s.
> >> >
> >> > Any interest?
> >>
> >> You bet :)
> >>
> >> Isn't that like proper part of the transput? We are interested on the
> >> rest of it as well! ^^
> >>
> >>
> > Ok, Nelson indicated that he has a brief period to review the code, so I
> > sent it to him; I'm happy to share it here, or send it privately to
> anyone
> > who wants to take a look, whichever seems most appropriate. Also, it's a
> > complete rewrite, so I don't want to claim that it's ready for prime
> time.
> >
> > I want to work on the fixed and float procedures as well, but I'd like to
> > use the state-of-the art algorithms, either Schubfach or Dragonbox, based
> > on evaluations conducted in this paper:
> >
> > https://r-libre.teluq.ca/3943/1/floatserialize.pdf
> >
> > I'm not feeling like that is a trivial solution (given that I haven't yet
> > grasped the subtlety of Schubfach), but I think it's worth it.
>
> Can we assume that at some point this will be included in a patch for
> standard.a68.in that adds th transput? Or a patch adding a
> transput.a68.in?
>
I've had a response from Nelson about my proposed new whole and I've asked
him if I can share it. Meanwhile I'm trying to think how to best do some
serious verification before I offer it to all.
I've run the same test Nelson did over int, long int, long long int, short
int and short short int, and I think the results look fine:
m = +2147483647
-m - 0 = -2147483647
-m - 1 = -2147483648
-m - 2 = +2147483647
-m - 3 = +2147483646
-m - 4 = +2147483645
-m - 5 = +2147483644
-m - 6 = +2147483643
lm = +9223372036854775807
-lm - 0 = -9223372036854775807
-lm - 1 = -9223372036854775808
-lm - 2 = +9223372036854775807
-lm - 3 = +9223372036854775806
-lm - 4 = +9223372036854775805
-lm - 5 = +9223372036854775804
-lm - 6 = +9223372036854775803
llm = +9223372036854775807
-llm - 0 = -9223372036854775807
-llm - 1 = -9223372036854775808
-llm - 2 = +9223372036854775807
-llm - 3 = +9223372036854775806
-llm - 4 = +9223372036854775805
-llm - 5 = +9223372036854775804
-llm - 6 = +9223372036854775803
sm = +32767
-sm - 0 = -32767
-sm - 1 = -32768
-sm - 2 = +32767
-sm - 3 = +32766
-sm - 4 = +32765
-sm - 5 = +32764
-sm - 6 = +32763
ssm = +127
-ssm - 0 = -127
-ssm - 1 = -128
-ssm - 2 = +127
-ssm - 3 = +126
-ssm - 4 = +125
-ssm - 5 = +124
-ssm - 6 = +123
I've another test over -max_int - 1 to max_int stepping by 100 and 1000.
Using 'time', this took
real 0m9.828s
user 0m1.591s
sys 0m8.228s
and produced a file with 4.294.968 lines in it. The first 10 lines look
like this:
-2147483648
-2147482648
-2147481648
-2147480648
-2147479648
-2147478648
-2147477648
-2147476648
-2147475648
-2147474648
and the last 10 like this:
2147474352
2147475352
2147476352
2147477352
2147478352
2147479352
2147480352
2147481352
2147482352
2147483352
Again, this seems good to me. Just in case there's some weird stuff
somewhere in the middle, I've checked the results against a C program
looping over integers and printing with printf, and the diffs show they are
the same.
By the way I think it's very cool that the Algol 68 program did not sail
off into the ozone because the loop variable wrapped around; my dumb 1st
attempt C program did...
I'm happy to propose a patch but since my code is not just a few tweaks
here and there on the RR code, I think it would be good if someone took a
look first and maybe kicked the tires a bit.
--
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/20260710/0017090f/attachment.htm>
More information about the Algol68
mailing list