Ramblings on converting L int, L real to string
chris hermansen
clhermansen@gmail.com
Thu Aug 21 18:02:44 GMT 2025
Hello all,
Because GNU Algol 68 doesn't have all the formatted transput stuff, I have
been spending some spare time creating the following unary operators:
TOS - int, long int to string, with no thousands separators
TOSS - int, long int to string, with thousands separators
TOSB - int, long int, bits, long bits to binary string
representation
TOSX - int, long int, bits, long bits to hexadecimal string
representation
TOSE - real, long real to scientific notation string, matching C
'e' format string
TOSF - real, long real to fixed decimal string, matching C 'f'
format string
(I previously threw together more-or-less working whole() and fixed()
procedures, but I've never been that enamoured with their described
implementations in the Revised Report - for example, leading plus signs -
so I decided to go a separate way).
For the int and long int to string (as decimal numbers) I decided to have
the operator that takes an int argument just lengthen that and pass it to
the single formatting function that takes the long int version. For
example,
{ Operators to convert int, long int to string with no thousands separators
}
op TOS = (int number) string: begin
tos_format_long_int(LENG number, false)
end { TOS };
op TOS = (long int number) string: begin
tos_format_long_int(number, false)
end { TOS };
(the third boolean argument indicates whether or not to use thousands
separators).
Obviously I could have done this with a union and a conformity clause, but
since operators can be overloaded I find I prefer this separate approach.
However, when it came to the operators for int, long int, bits and long
bits to string, I found myself defining
op TOSB = (union (int, bits) v) string: begin
...
end { TOSB };
op TOSB = (union (long int, long bits) v) string: begin
...
end { TOSB };
and similarly for the TOSX operator. I did this because I each operator
deals with both int and bits, long int and long bits, so it seems somehow
the right way to proceed.
Finally, the real, long real to scientific notation and to fixed decimal...
wow a lot of lessons learned there.
First lesson, which I have learned before at some cost in time in
frustration (so why not learn it again?) - it's not easy to get good
results. I found this paper to be salutary reading (the Google Drive link
is given on Wikipedia, which seems unusual, but at least when I followed
it, I did turn up the anticipated PDF):
https://drive.google.com/file/d/1IEeATSVnEE6TkrHlCYNY2GjaraBjOT4f
The TL;DR in this exposé is:
1. not every prime dividing 10, the radix of the decimals, also divides
2, the radix of the floating point binary;
2. since any decimal number D that rounds to a finite positive binary
floating point representation v is as good as v itself for the purpose
of rendering, one might as well choose the decimal number dv as the
shortest such
The author provides this interesting example:
Example 1. Let double v = 20 · 2−1074 = 9.88 . . . · 10−323 , whose full
> decimal expansion has the unwieldy length of 750, really! The definition
> determines
> R = {1 · 10−322 , 97 · 10−324 , 98 · 10−324 , 99 · 10−324 , . . . (longer
> decimals)}
> m = 1,
> T = {1 · 10−322 }
> and selects dv = 1 × 10−322 as the only element in T , which is formatted
> as 1.0E-322. Since there’s room for 2 digits anyway, a better choice would
> be 99 × 10−324 . Although longer in the sense of §3.2, it is closer to v
> (and closer than 98 × 10−324 , the other close decimal of length 2), yet
> still requiring only two digits when formatted: 9.9E-323. Closer, albeit
> longer decimals of length up to 2 are preferred over shorter but farther
> ones.
The author develops the concepts further and then goes on to present the
Shubfach algorithm. At this point I was getting excited... until I saw
this phrase:
With this information at hand, the determination of v̄ = ro′ (4V ′ ) can
> proceed by bit twiddling as follows
That stopped me in my tracks, since of course Algol 68 has no BIN operator
defined on real, long real, etc.
So I went back to dividing and multiplying by 10 to get an integral
significand and an exponent that I could convert to strings and then insert
the string decimal point in the correct position.
I found that in order to get formatted numbers that generally matched those
produced by C's stdio library, I had to use long real to handle real
conversions and long long real to handle long real conversions. Or so it
seemed, anyway...
So in the floating point case, because of my residual uncertainty, I have
kept the code that computes integral long real significand (for real
numbers) and integral long long real significand (for long real numbers)
separate, though I could in principle use the long long real code for
formatting both real and long real numbers.
Finally, I have tested these operators and they seem to produce decently
correct results. I'm happy to share the code under GNU GPL v3+ with anyone
who is interested.
And I would love to have feedback, comments, brickbats...
--
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/20250821/85cf432c/attachment.htm>
More information about the Algol68
mailing list