Discussion:
128 bit integers
(too old to reply)
jacob navia
2005-07-28 13:10:11 UTC
Permalink
A customer has asked me to add 128 bit integers to the 64 bit
version of my compiler system (lcc-win64).

After developing the assembly procedures, I have several
questions:

1) How should I name this stuff?
long long long ???
__int128 ?
int128 ?

2) How would this integers get printed with printf?
"%llld" ?
"%I128d" ?

3) Should I supply definitions for it in inttypes.h, and in
stdint.h ?

4) What other implications can this new type have? I would have
loved to use long long for this, long for 64 bit, int for 32
bits, etc. But this is not possible for compatibility reasons.
There is too much software there that assumes long long is 64 bits,
not 128.

jacob

http://www.cs.virginia.edu:/~lcc-win32
jacob navia
2005-07-28 13:12:52 UTC
Permalink
Excuse me, I forgot another problem:

5) The string --> 128 bit integer procedure should be
strtolll ?
strtoi128 ?
strto128 ?
Niklas Matthies
2005-07-28 16:00:27 UTC
Permalink
Post by jacob navia
A customer has asked me to add 128 bit integers to the 64 bit
version of my compiler system (lcc-win64).
After developing the assembly procedures, I have several
1) How should I name this stuff?
long long long ???
__int128 ?
int128 ?
It should be a reserved name, e.g. __int128, and <stdint.h> should
provide a typedef int128_t to it.
Post by jacob navia
3) Should I supply definitions for it in inttypes.h, and in
stdint.h ?
Certainly. You want the customer to be able to portably use that type,
don't you?

-- Niklas Matthies
Chris Croughton
2005-07-28 15:31:10 UTC
Permalink
On Thu, 28 Jul 2005 15:10:11 +0200, jacob navia
Post by jacob navia
4) What other implications can this new type have? I would have
loved to use long long for this, long for 64 bit, int for 32
bits, etc. But this is not possible for compatibility reasons.
There is too much software there that assumes long long is 64 bits,
not 128.
Any software which assumes any specific size of a type is broken.
Certainly with long long, which hasn't been around for very long
(apologies for the pun) so hasn't got the excuse of "there were only 16
bit machines around when we wrote it". long long is /at least/ 64 bits,
it could easily be 72 on a 24 bit machine for instance.

Probably just adding the new type to stdint.h and inttypes.h with
appropriate macros would be adequate. An implementation can happily
define types of form intN_t and uintN_t (and the least and fast
variations) and the PRIdN (etc.) macros without encroaching on the user
namespace in those headers.

Since, however, the macros and types should not be defined if the
headers are not included, the underlying type should be in the
implementation namespace, starting with underscore (so _int128_t and
_uint128_t would be reasonable) unless you can easily detect which
header is included and switch the keywords off. long long long is silly
in my view (as is long long).

Chris C
jacob navia
2005-07-28 17:32:10 UTC
Permalink
Post by Chris Croughton
Any software which assumes any specific size of a type is broken.
Certainly with long long, which hasn't been around for very long
(apologies for the pun) so hasn't got the excuse of "there were only 16
bit machines around when we wrote it". long long is /at least/ 64 bits,
it could easily be 72 on a 24 bit machine for instance.
The windows version of the compiler system has to conform to
the 64 bit ABI as specified by Microsoft Corp.
int --> 32 bits
long --> 32 bits
void * --> 64 bits
long long --> 64 bits. Microsoft names this __int64.

I have to follow that. No way out.

Under linux the ABI I had to follow looks like this:

int --> 32 bits
long --> 64 bits
void * --> 64 bits
long long --> 64 bits.

jacob

P.S. Did you notice that 64 bit windows specified that
a pointer does NOT fit into a long ? This will surely provoke
some headaches.

jacob
Chris Croughton
2005-07-28 21:11:48 UTC
Permalink
On Thu, 28 Jul 2005 19:32:10 +0200, jacob navia
Post by jacob navia
Post by Chris Croughton
Any software which assumes any specific size of a type is broken.
Certainly with long long, which hasn't been around for very long
(apologies for the pun) so hasn't got the excuse of "there were only 16
bit machines around when we wrote it". long long is /at least/ 64 bits,
it could easily be 72 on a 24 bit machine for instance.
The windows version of the compiler system has to conform to
the 64 bit ABI as specified by Microsoft Corp.
int --> 32 bits
long --> 32 bits
void * --> 64 bits
long long --> 64 bits. Microsoft names this __int64.
I have to follow that. No way out.
If it's the Application /Binary/ Interface then you don't have a
problem, because you can call the types whatever you like and the ABI
won't know any different. If you have to work with the MS broken
headers, then you have a problem (yes, broken, they won't even compile
without warnings using MSVC!).
Post by jacob navia
int --> 32 bits
long --> 64 bits
void * --> 64 bits
long long --> 64 bits.
Who says long long has to be 64 bits on Linux? Again, if the ABI is
specified as taking a 64 bit value you can just as easily pass a long to
it. Or better an int64_t.
Post by jacob navia
P.S. Did you notice that 64 bit windows specified that
a pointer does NOT fit into a long ? This will surely provoke
some headaches.
Will it? Possibly for some people used to writing non-portable
programs. Poor things, they may finally have to wake up to what real
programmers have been saying for years, that you can't depend on
any sizes other than the minima in the standard and that converting
between pointers and integer types is inherently dangerous. Lazy
programmers taking shortcuts deserve to get bitten...

Chris C
Jack Klein
2005-07-28 16:30:18 UTC
Permalink
On Thu, 28 Jul 2005 15:10:11 +0200, jacob navia
Post by jacob navia
A customer has asked me to add 128 bit integers to the 64 bit
version of my compiler system (lcc-win64).
After developing the assembly procedures, I have several
1) How should I name this stuff?
long long long ???
__int128 ?
int128 ?
I agree with Niklas, name them __int128 and __uint128, or something
similar beginning with "__" to keep them in the implementation name
space.

In stdint.h, typedef them as int128_t and uint128_t, and also as the
least128 and fast128 types. And absolutely as intmax_t and uintmax_t.
Post by jacob navia
2) How would this integers get printed with printf?
"%llld" ?
"%I128d" ?
"%llld" and "%lllu" are not so bad, I guess. One of the reasons why I
never particularly liked "long long", aside from the fact that
spelling checkers always point out the repeated word, is that by the
time we get to 1024 bit processors, we'll have "long long long spam
and long".

Also the inttypes.h macros for "PRId128", "PRIo128", "PRIu128",
"PRIx128", and the least/fast, plus the intmax ones.
Post by jacob navia
3) Should I supply definitions for it in inttypes.h, and in
stdint.h ?
I would say yes, that way you can make it strictly conforming.
Post by jacob navia
4) What other implications can this new type have? I would have
loved to use long long for this, long for 64 bit, int for 32
bits, etc. But this is not possible for compatibility reasons.
There is too much software there that assumes long long is 64 bits,
not 128.
I have a thought about the compatibility issue. If you add the
specific 128 bit typedefs and macros, the extensions become 100%
strictly conforming. The only extension you are adding are the two
native conversion specifiers for *printf() and *scanf().

But where you might run into a problem is with intmax_t and uintmax_t,
for the same reason as long long. If your longest type has 128 bits,
the standard requires that you use it for max types. But there is any
Win64 code that uses intmax_t and uintmax_t, it is likely to assume
they are 64 bits, just like long long.

Perhaps you might want to have inttypes.h and stdint.h default to
keeping the max types at 64 bits unless a particular macro or compiler
command line option is defined. That makes it non-conforming by
default, but then again I have never seen a compiler that wasn't, when
invoked with its default arguments.

Are you planning on releasing this compiler under a free for
non-commercial use as you have with your 32-bit version?
Post by jacob navia
jacob
http://www.cs.virginia.edu:/~lcc-win32
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
Douglas A. Gwyn
2005-07-28 23:06:40 UTC
Permalink
... But there is any
Win64 code that uses intmax_t and uintmax_t, it is likely to assume
they are 64 bits, just like long long.
Hopefully that's not in the Win64 ABI; it shouldn't be.
It is *very* important that [u]intmax_t be wide enough to
hold any value of *any* supported integer type, not just
the standard integer types. In fact that's its semantics.
Jack Klein
2005-07-29 03:01:38 UTC
Permalink
Post by Douglas A. Gwyn
... But there is any
Win64 code that uses intmax_t and uintmax_t, it is likely to assume
they are 64 bits, just like long long.
Hopefully that's not in the Win64 ABI; it shouldn't be.
It is *very* important that [u]intmax_t be wide enough to
hold any value of *any* supported integer type, not just
the standard integer types. In fact that's its semantics.
I have no idea about the Win64 ABI, I just know lots of Windows
programmers.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
Douglas A. Gwyn
2005-07-29 14:32:35 UTC
Permalink
Post by Jack Klein
Post by Douglas A. Gwyn
... But there is any
Win64 code that uses intmax_t and uintmax_t, it is likely to assume
they are 64 bits, just like long long.
Hopefully that's not in the Win64 ABI; it shouldn't be.
It is *very* important that [u]intmax_t be wide enough to
hold any value of *any* supported integer type, not just
the standard integer types. In fact that's its semantics.
I have no idea about the Win64 ABI, I just know lots of Windows
programmers.
I hope you're not saying that they are uniformly incompetent.
The very *definition* of [u]intmax_t implies that its only
reasonable use is as a maximum-width container in a context
where the programmer must ensure that some arbitrary,
unknown-width integer type can fit into it, including
whatever extended integer types the implementation might
support in addition to the standard integer types. In any
context where only widths up to [unsigned] long long need be
accommodated, surely [unsigned] long long would be used.
Further, since the only way to use [u]intmax_t is via
<stdint.h> (or <inttypes.h>), which provides *other* typedef
names for integer types with the exactly-64-width property,
surely the programmer would be using the latter if that is
the property he requires.

Anyway, it would be a serious mistake for an implementation
to provide (extended) integer types wider than its definition
for [u]intmax_t; for one thing it would fail to conform to
the standard, which would certainly cause problems.
a***@myrealbox.com
2005-08-05 13:47:30 UTC
Permalink
Post by Douglas A. Gwyn
I hope you're not saying that they are uniformly incompetent.
The very *definition* of [u]intmax_t implies that its only
reasonable use is as a maximum-width container in a context
where the programmer must ensure that some arbitrary,
unknown-width integer type can fit into it, including
whatever extended integer types the implementation might
support in addition to the standard integer types.
Can you give sample code for such a reasonable use?
How would the programmer encounter such an arbitrary type?
It can't be the result of a promotion, nor the result of a
standard library function.

The problem is where something like int256_t can be provided
(e.g. by use of SIMD units) but is significantly slower than
32-bit or 64-bit arithmetic, and possibly orders of magnitude
slower for some arithmetic operations.

If the implementation is then forced to define uintmax_t as
256 bits then it's constraining all users of uintmax_t to
take that performance hit - which makes it very much less
useful, hardly more useful than a suitably sized byte array.
k***@wizard.net
2005-08-05 15:04:52 UTC
Permalink
Post by a***@myrealbox.com
Post by Douglas A. Gwyn
I hope you're not saying that they are uniformly incompetent.
The very *definition* of [u]intmax_t implies that its only
reasonable use is as a maximum-width container in a context
where the programmer must ensure that some arbitrary,
unknown-width integer type can fit into it, including
whatever extended integer types the implementation might
support in addition to the standard integer types.
Can you give sample code for such a reasonable use?
How would the programmer encounter such an arbitrary type?
It can't be the result of a promotion, nor the result of a
standard library function.
We routinely work with several different third-party libraries that
provide various typedefs. Let's take PGSt_integer as a typical one of
these typedefs. The vendor's documentation makes no promises about
which type it is, other than the fact that it's signed integer type.
It's possible to indirectly prove that it must be at least 32 bits
wide, but even that's not stated explicitly. In reality, it's typedef'd
to different types on different platforms. The header files we
currently have installed don't typedef it to any type wider than 'long'
on any platform; however, the installation script for that library
installs different header files on different platforms, so it's
concievable that it's typedef'd to something longer on one of the
platforms we don't use (our code is still required to be portable to
those platforms). In any event, even if that is currently true for all
platforms, there's no guarantees that it will be true for all platforms
in future versions of that library. Therefore the only safe way to
print out PGSt_integer values is :

printf("i=%jd\n", (intmax_t)i);
Post by a***@myrealbox.com
The problem is where something like int256_t can be provided
(e.g. by use of SIMD units) but is significantly slower than
32-bit or 64-bit arithmetic, and possibly orders of magnitude
slower for some arithmetic operations.
If the implementation is then forced to define uintmax_t as
256 bits then it's constraining all users of uintmax_t to
take that performance hit - which makes it very much less
useful, hardly more useful than a suitably sized byte array.
If you're certain that all of the values that need to be represented
will fit in a 64 bit signed type, and speed is important, you should
use int_fast64_t. You should use uintmax_t only if you're NOT certain
that all of the values will fit in 64 bits.
a***@myrealbox.com
2005-08-08 08:05:40 UTC
Permalink
Post by k***@wizard.net
in future versions of that library. Therefore the only safe way to
printf("i=%jd\n", (intmax_t)i);
No, you could do the binary-to-decimal conversion by hand,
if sizeof indicated that the type was wider than any you
knew the formats for. You'd have had to do this under C89.
If PGSt_integer happened to be 'short', and intmax_t
happened to be 'int256_t', this would likely be faster
than your code.

In any case, you only have this problem if the vendor doesn't
define a printf format macro for this type (like the ones
in inttypes.h). Defining such a macro is surely now the
standard way to do things.
Post by k***@wizard.net
If you're certain that all of the values that need to be represented
will fit in a 64 bit signed type, and speed is important, you should
use int_fast64_t. You should use uintmax_t only if you're NOT certain
that all of the values will fit in 64 bits.
Correct. The question is how often such situations occur.
k***@wizard.net
2005-08-08 13:16:15 UTC
Permalink
Post by a***@myrealbox.com
Post by k***@wizard.net
in future versions of that library. Therefore the only safe way to
printf("i=%jd\n", (intmax_t)i);
No, you could do the binary-to-decimal conversion by hand,
Why would I want to write complicated code like that, when "%jd"
exists? It wouldn't be hard to write, but even the minimal time it
would take me to write and document it cost my employer a lot more
money than the extra time printf() would spend in the rare case that
the printf() call was slower than such code. I think implementations
which provide only an extremely slow and inefficient implementation of
their largest integral type are not common; as a practical matter, none
of the compilers we currently use fit that description.
Post by a***@myrealbox.com
If PGSt_integer happened to be 'short', and intmax_t
happened to be 'int256_t', this would likely be faster
than your code.
Yes, but as I've said, I have no guarantees on the width of
PGSt_integer, except an implicitly derivable one that it be more than
32 bits. It's more likely to be the same type as int_fast32_t than it
is to be 'short'. It's typical for typedefs that no upper limit on
their width, to have a moderately high lower limit.
Post by a***@myrealbox.com
In any case, you only have this problem if the vendor doesn't
define a printf format macro for this type (like the ones
in inttypes.h). Defining such a macro is surely now the
standard way to do things.
Perhaps; but that doesn't do me any good if the vendor hasn't actually
adopted that way (as he hasn't).
Post by a***@myrealbox.com
Post by k***@wizard.net
If you're certain that all of the values that need to be represented
will fit in a 64 bit signed type, and speed is important, you should
use int_fast64_t. You should use uintmax_t only if you're NOT certain
that all of the values will fit in 64 bits.
Correct. The question is how often such situations occur.
In my own experience, pretty frequently. Your experience may be
different.
Chris Croughton
2005-08-08 15:46:35 UTC
Permalink
Post by k***@wizard.net
Post by a***@myrealbox.com
Post by k***@wizard.net
in future versions of that library. Therefore the only safe way to
printf("i=%jd\n", (intmax_t)i);
No, you could do the binary-to-decimal conversion by hand,
Why would I want to write complicated code like that, when "%jd"
exists?
Because on many systems it /doesn't/ exist. It's why I've been writing
my own C99 compliant[1] implementation of printf and friends, because
many systems do not yet have C99 libraries even when they have C99
compilers (or close facsimiles like recent versions of GCC).

[1] There is no way as far as I can tell to portable handle some of the
necessary floating point conversions, line NaNs and infinities. They
could be handled if the platform is known to implement some particular
FP model but there is no standard way of determining that.
Post by k***@wizard.net
Post by a***@myrealbox.com
In any case, you only have this problem if the vendor doesn't
define a printf format macro for this type (like the ones
in inttypes.h). Defining such a macro is surely now the
standard way to do things.
Perhaps; but that doesn't do me any good if the vendor hasn't actually
adopted that way (as he hasn't).
So the vendor has inplemented the printf-family 'j' modifier but hasn't
provided the macros? Sounds like a fairly typical half-arsed C99
implementation to me, but in my experience it's more often the other way
round (the macros are there but the library isn't).
Post by k***@wizard.net
Post by a***@myrealbox.com
Post by k***@wizard.net
If you're certain that all of the values that need to be represented
will fit in a 64 bit signed type, and speed is important, you should
use int_fast64_t. You should use uintmax_t only if you're NOT certain
that all of the values will fit in 64 bits.
Correct. The question is how often such situations occur.
In my own experience, pretty frequently. Your experience may be
different.
Indeed. The only times I've needed something more than 64 bits I've
implemented it myself because I can't depend on any system providing
such a type -- and that implementation can't be conveniently cast to
a standard integer type anyway in C with any meaningful results. I
would rather get a diagnostic about trying to cast a structure to an
integer type, so I know something is wrong...

Chris C
k***@wizard.net
2005-08-08 18:13:21 UTC
Permalink
Post by Chris Croughton
Post by k***@wizard.net
Post by a***@myrealbox.com
Post by k***@wizard.net
in future versions of that library. Therefore the only safe way to
printf("i=%jd\n", (intmax_t)i);
No, you could do the binary-to-decimal conversion by hand,
Why would I want to write complicated code like that, when "%jd"
exists?
Because on many systems it /doesn't/ exist.
If you don't have a conforming C99 compiler, then the best possible
substitute for intmax_t is 'long'; if that isn't big enough, then
you'll have to give up on portability and write code that's specific to
the platform you're using. However, platforms where only C90 is
available, and 'long' isn't big enough, are rare enough in my
experience that I don't bother worrying about them. As always, your
experience may differ.
Post by Chris Croughton
Post by k***@wizard.net
Post by a***@myrealbox.com
In any case, you only have this problem if the vendor doesn't
define a printf format macro for this type (like the ones
in inttypes.h). Defining such a macro is surely now the
standard way to do things.
Perhaps; but that doesn't do me any good if the vendor hasn't actually
adopted that way (as he hasn't).
So the vendor has inplemented the printf-family 'j' modifier but hasn't
provided the macros?
No, I'm referring to the vendor that provided a third-party library.
I'm referring to the format string that corresponds to that third party
library's PGSt_integer typedef, which is almost certainly not "%jd".
The printf() family isn't their responsibility. Providing a macro that
contains a suitable format string would be a good idea, but it wasn't
actually done.
Post by Chris Croughton
Post by k***@wizard.net
Post by a***@myrealbox.com
Post by k***@wizard.net
If you're certain that all of the values that need to be represented
will fit in a 64 bit signed type, and speed is important, you should
use int_fast64_t. You should use uintmax_t only if you're NOT certain
that all of the values will fit in 64 bits.
Correct. The question is how often such situations occur.
In my own experience, pretty frequently. Your experience may be
different.
Indeed. The only times I've needed something more than 64 bits I've
If I didn't have a responsibility to the future, it would be easy. We
don't use any compiler that supports a type with more than 64 bits, so
if I didn't have to worry about upward compatibility I could use
int_fast64_t for all such purposes. However, my code is supposed to
continue working correctly even when compiled by an implementation of C
that does support a 128 bit type, so long as it supports it in a
conforming fashion, even if every third-party typedef that has no
conflicting constraints on it gets updated to refer to int128_t.
Chris Croughton
2005-08-08 20:35:01 UTC
Permalink
Post by k***@wizard.net
Post by Chris Croughton
Post by k***@wizard.net
Why would I want to write complicated code like that, when "%jd"
exists?
Because on many systems it /doesn't/ exist.
If you don't have a conforming C99 compiler,
/and library/
Post by k***@wizard.net
then the best possible
substitute for intmax_t is 'long'; if that isn't big enough, then
you'll have to give up on portability and write code that's specific to
the platform you're using.
No, you can write portable conversion code for it. Last time I did that
it took me under half an hour (generic base (2 to 36) input and output)
including testing. I don't have to write it again. The only thing
which may not be portable about it is handling the biggest negative
integer when that is larger in magnitude than the biggest positive
integer (it may, on some odd machines, generate an overflow trap) and
similarly for detecting overflow on input, but those could easily be
conditionally compiled (I haven't found any need to yet, however).
Post by k***@wizard.net
However, platforms where only C90 is
available, and 'long' isn't big enough, are rare enough in my
experience that I don't bother worrying about them. As always, your
experience may differ.
Any platform with gcc the /compiler/ supports intmax_t (gcc should
install stdint.h if it doesn't exist). However, the /library/ very
often does not support the 'j' modifier because gcc uses the system C
library. The same with the rest of the C99 additions to the library
(the long double versions of the maths functions, for instance). That's
quite a lot of platforms (and I don't think gcc is alone in that)...
Post by k***@wizard.net
Post by Chris Croughton
Post by k***@wizard.net
Perhaps; but that doesn't do me any good if the vendor hasn't actually
adopted that way (as he hasn't).
So the vendor has inplemented the printf-family 'j' modifier but hasn't
provided the macros?
No, I'm referring to the vendor that provided a third-party library.
I'm referring to the format string that corresponds to that third party
library's PGSt_integer typedef, which is almost certainly not "%jd".
The printf() family isn't their responsibility. Providing a macro that
contains a suitable format string would be a good idea, but it wasn't
actually done.
Well, that's a QoI issue with your vendor.
Post by k***@wizard.net
Post by Chris Croughton
Indeed. The only times I've needed something more than 64 bits I've
If I didn't have a responsibility to the future, it would be easy. We
don't use any compiler that supports a type with more than 64 bits, so
if I didn't have to worry about upward compatibility I could use
int_fast64_t for all such purposes. However, my code is supposed to
continue working correctly even when compiled by an implementation of C
that does support a 128 bit type, so long as it supports it in a
conforming fashion, even if every third-party typedef that has no
conflicting constraints on it gets updated to refer to int128_t.
Code should be designed for the values which are reasonable in the
problem domain, not whatever types the compiler may produce in the
future. Cases where I don't know that the range of a variable won't fit
into 64 bits are vanishingly rare, ones where it may not fit into 32
bits in the future are pretty rare (the main one being a time difference
in seconds). But the point is that unless you implement the conversion
yourself you still have no guarantee of future-proof code, because the
compiler may implement intmax_t as 128 bits but the library (which you
say isn't provided by the same supplier as the compiler) may not support
it and you'll be stuffed if you cast to intmax_t.

Personally, if I know that the value in the problem domain will fit in
32 bits I cast to long, if it will fit in than 64 bits I may cast to
long long (but I may not, because not all C libraries support the ll
qualifier) otherwise I use my own which also supports strange bases (why
anyone would want to input or output in base 17 or 23 I don't know, but
it costs more to block 'silly' bases than to allow them; I block bases
less than 2 (infinite loops) and above 36 (runs off the end of the
array) and allow everything else).

Chris C
k***@wizard.net
2005-08-09 17:11:16 UTC
Permalink
Post by Chris Croughton
Post by k***@wizard.net
Post by Chris Croughton
Post by k***@wizard.net
Why would I want to write complicated code like that, when "%jd"
exists?
Because on many systems it /doesn't/ exist.
If you don't have a conforming C99 compiler,
/and library/
Sorry, I should have said "implementation" rather than "compiler".
Post by Chris Croughton
Post by k***@wizard.net
then the best possible
substitute for intmax_t is 'long'; if that isn't big enough, then
you'll have to give up on portability and write code that's specific to
the platform you're using.
No, you can write portable conversion code for it. Last time I did that
it took me under half an hour (generic base (2 to 36) input and output)
If it took you a half hour to write it, then it would require several
hours of testing and writing up of documentation, in order to permit it
to be used as part of our software. The total cost to my employer of my
salary for that amount of time would exceed by several orders of
magnitude the value of the expected savings in CPU time (and I'm not
claiming to be exceptionally well paid).
Post by Chris Croughton
Post by k***@wizard.net
However, platforms where only C90 is
available, and 'long' isn't big enough, are rare enough in my
experience that I don't bother worrying about them. As always, your
experience may differ.
Any platform with gcc the /compiler/ supports intmax_t (gcc should
install stdint.h if it doesn't exist). However, the /library/ very
often does not support the 'j' modifier because gcc uses the system C
library. The same with the rest of the C99 additions to the library
(the long double versions of the maths functions, for instance). That's
quite a lot of platforms (and I don't think gcc is alone in that)...
Since the library doesn't support the 'j' modifier, the
compiler+library doesn't constitute a conforming implementation of C99.

It might conform with C90, in which case my previous comments about
'long' apply; the fact that there's a possible typedef for intmax_t
doesn't affect the validity of those comments. It should have intmax_t
as a typedef for 'long' and PRIdMAX should expand to "%ld", and I'm not
willing to worry about the exceptional cases where that's wrong. If it
doesn't conform to either standard, it's off-topic for this newsgroup.

...
Post by Chris Croughton
Post by k***@wizard.net
No, I'm referring to the vendor that provided a third-party library.
I'm referring to the format string that corresponds to that third party
library's PGSt_integer typedef, which is almost certainly not "%jd".
The printf() family isn't their responsibility. Providing a macro that
contains a suitable format string would be a good idea, but it wasn't
actually done.
Well, that's a QoI issue with your vendor.
Yes, but since it's also an fairly commonplace type of QoI issue, it
also qualifies as a legitimate reason for needing intmax_t and "%jd".
Post by Chris Croughton
Post by k***@wizard.net
If I didn't have a responsibility to the future, it would be easy. We
don't use any compiler that supports a type with more than 64 bits, so
if I didn't have to worry about upward compatibility I could use
int_fast64_t for all such purposes. However, my code is supposed to
continue working correctly even when compiled by an implementation of C
that does support a 128 bit type, so long as it supports it in a
conforming fashion, even if every third-party typedef that has no
conflicting constraints on it gets updated to refer to int128_t.
Code should be designed for the values which are reasonable in the
problem domain, not whatever types the compiler may produce in the
future.
The problem domain includes, in this case, use of PGSt_integer to store
ID codes that are assigned by a program that comes with the library, in
accordance with an undocumented algorithm (as users of the library,
we're not supposed to know or care what that algorithm is), which might
(and currently does) use the full range of values available to
PGSt_integer. Source code for that program is available (but keep in
mind that the installation script installs different source code on
different platforms). However, since there's no promise that the
algorithm will remain the same in future versions, no responsible
programmer should bother examining that source code to determine what
the possible range of values is.
Post by Chris Croughton
... Cases where I don't know that the range of a variable won't fit
into 64 bits are vanishingly rare, ones where it may not fit into 32
bits in the future are pretty rare (the main one being a time difference
in seconds). But the point is that unless you implement the conversion
yourself you still have no guarantee of future-proof code, because the
compiler may implement intmax_t as 128 bits but the library (which you
say isn't provided by the same supplier as the compiler) may not support
it and you'll be stuffed if you cast to intmax_t.
The library is provided as source code (different source code for
different platforms, with lots of conditional compilation). If, after
conditional compilation, the source code for a given platform requires
int128_t, and the compiler we use doesn't support that type, the
library won't even compile. As a user of this library, that's not a
problem I have to worry about.

However, I also happen to be the person responsible for installing this
library; in that capacity, if the compiler I'm using is one that the
library is certified to work with, I would report the failure as a bug
back to the vendor. On the other hand, if the third-party library's
header files typedef PGSt_integer as int128_t, and fails to provide a
corresponding format string macro, I can't label those as bugs, because
neither of those possibilities violate any promises the vendor has
made.
a***@myrealbox.com
2005-08-12 16:01:52 UTC
Permalink
Post by k***@wizard.net
If it took you a half hour to write it, then it would require several
hours of testing and writing up of documentation, in order to permit it
to be used as part of our software. The total cost to my employer of my
salary for that amount of time would exceed by several orders of
magnitude the value of the expected savings in CPU time (and I'm not
claiming to be exceptionally well paid).
If mere productivity is your goal, you'd likely be writing in C++
where the whole issue is solved by writing "cout << n".

The decision to go from C89 to C99 rather than C++, indicates
certain priorities. With those priorities in mind, I would
not write code where the resulting object was affected by the
implementation's decision to introduce a new type.

So I wouldn't use [u]intmax_t, because the minute the implementation
introduces int128_t - irrespective of the fact that nothing makes
explicit reference to it - my code ends up meaning something different.
Possibly it drags in the 128-bit arithmetic software support library,
or a more heavyweight implementation of printf, or whatever, and my
program gets whole kilobytes larger and no longer fits into its ROM.

If I'm in the C99 niche, I care about such things.
k***@wizard.net
2005-08-12 17:52:46 UTC
Permalink
Post by a***@myrealbox.com
Post by k***@wizard.net
If it took you a half hour to write it, then it would require several
hours of testing and writing up of documentation, in order to permit it
to be used as part of our software. The total cost to my employer of my
salary for that amount of time would exceed by several orders of
magnitude the value of the expected savings in CPU time (and I'm not
claiming to be exceptionally well paid).
If mere productivity is your goal, you'd likely be writing in C++
where the whole issue is solved by writing "cout << n".
I'd like to; but C++ isn't an option permitted by the contract I'm
currently working under.
Post by a***@myrealbox.com
The decision to go from C89 to C99 rather than C++, indicates
certain priorities. With those priorities in mind, I would
not write code where the resulting object was affected by the
implementation's decision to introduce a new type.
So I wouldn't use [u]intmax_t, because the minute the implementation
introduces int128_t - irrespective of the fact that nothing makes
explicit reference to it - my code ends up meaning something different.
Possibly it drags in the 128-bit arithmetic software support library,
or a more heavyweight implementation of printf, or whatever, and my
program gets whole kilobytes larger and no longer fits into its ROM.
The only time I'd ever use intmax_t is if I explicitly wanted it to
change, in precisely the way you describe, when the implementation
added a new type. I've found more situations where I want that to
happen (for the reasons I've already explained) than situations where I
knew, for certain, that 64 bits would be sufficient, while 32 bits was
not.
jacob navia
2005-08-13 21:26:20 UTC
Permalink
Post by a***@myrealbox.com
Post by k***@wizard.net
If it took you a half hour to write it, then it would require several
hours of testing and writing up of documentation, in order to permit it
to be used as part of our software. The total cost to my employer of my
salary for that amount of time would exceed by several orders of
magnitude the value of the expected savings in CPU time (and I'm not
claiming to be exceptionally well paid).
If mere productivity is your goal, you'd likely be writing in C++
where the whole issue is solved by writing "cout << n".
The decision to go from C89 to C99 rather than C++, indicates
certain priorities. With those priorities in mind, I would
not write code where the resulting object was affected by the
implementation's decision to introduce a new type.
So I wouldn't use [u]intmax_t, because the minute the implementation
introduces int128_t - irrespective of the fact that nothing makes
explicit reference to it - my code ends up meaning something different.
Possibly it drags in the 128-bit arithmetic software support library,
or a more heavyweight implementation of printf, or whatever, and my
program gets whole kilobytes larger and no longer fits into its ROM.
If I'm in the C99 niche, I care about such things.
Well, 128 bit integers were required for a customer
running in a desktop PC.
In an embedded environment, 32 bit integers are often
a luxury, so this whole discussion doesn't apply.

To give you an idea however, the whole i128 library
is (now) at approx 4K. It makes 1 million full 128
bit divisions in 1.5 seconds. Machine: Athlon,
using 32 bits software/OS. The 64 bit version should
be MUCH faster but this gives you an idea of the
speed in a 32 bit processor.
David R Tribble
2005-08-12 16:47:39 UTC
Permalink
Post by k***@wizard.net
Post by k***@wizard.net
I'm referring to the format string that corresponds to that third party
library's PGSt_integer typedef, which is almost certainly not "%jd".
The printf() family isn't their responsibility. Providing a macro that
contains a suitable format string would be a good idea, but it wasn't
actually done.
Well, that's a QoI issue with your vendor.
Yes, but since it's also an fairly commonplace type of QoI issue, it
also qualifies as a legitimate reason for needing intmax_t and "%jd".
Another possibility is to extend the printf format specifiers to
support an "integer width" argument, in order to handle integer
widths beyond the four standard widths. Perhaps something like
a '^' modifier, which indicates that another parameter is provided
that specifies the width of the parameter to format (similar to the
existing '*' modifier).

For example:

printf("%^d", sizeof(x), x);

where 'x' can be of any integer type supported by the implementation.

-drt
Keith Thompson
2005-08-12 17:21:06 UTC
Permalink
"David R Tribble" <***@tribble.com> writes:
[...]
Post by David R Tribble
Another possibility is to extend the printf format specifiers to
support an "integer width" argument, in order to handle integer
widths beyond the four standard widths. Perhaps something like
a '^' modifier, which indicates that another parameter is provided
that specifies the width of the parameter to format (similar to the
existing '*' modifier).
printf("%^d", sizeof(x), x);
where 'x' can be of any integer type supported by the implementation.
An implementation could do that. The standard could not, at least not
without adding a requirement that all signed integer types of a given
size are compatible, or excluding incompatible integer types (if any)
from being used with "%^d".
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Douglas A. Gwyn
2005-08-05 20:49:00 UTC
Permalink
Post by a***@myrealbox.com
Can you give sample code for such a reasonable use?
How would the programmer encounter such an arbitrary type?
It can't be the result of a promotion, nor the result of a
standard library function.
It could be a typedef, e.g. off_t. If you want to print the
value, it is easiest to cast it to the widest type and use
the corresponding format specifier.
Post by a***@myrealbox.com
The problem is where something like int256_t can be provided
(e.g. by use of SIMD units) but is significantly slower than
32-bit or 64-bit arithmetic, and possibly orders of magnitude
slower for some arithmetic operations.
Then intmax_t shall be slower. For its intended usage that
is not a problem.
Hallvard B Furuseth
2005-08-07 12:03:42 UTC
Permalink
Post by a***@myrealbox.com
The problem is where something like int256_t can be provided
(e.g. by use of SIMD units) but is significantly slower than
32-bit or 64-bit arithmetic, and possibly orders of magnitude
slower for some arithmetic operations.
When it really matters, you can write special cases for faster types.

if (LONG_MIN <= foo && foo <= LONG_MAX)
printf("%ld", (long) foo);
else
printf("%jd", (int256_t) foo);

Of course your printf %jd implementation may be doing that anyway.

Or if you want the branch chosen at compile time:

if ((unsigned_foo_t)-1 <= ULONG_MAX) ...

That doesn't work for signed types though. This variant is
wrong, since long can have padding bits:

if (sizeof(signed_foo_t) <= sizeof(long)) ... /* wrong */

Of course if they are the same size and long has padding bits,
it's likely that signed_foo_t has just as much padding, but
you don't know that for sure without checking.

You can write a configure script which finds the width of the
type and #defines it.


I wrote an IMAX_BITS macro to compute the number of bits in
the *_MAX macros at compile time once, but it's rather ugly:

/* Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 3.2E+10 */
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))

if (sizeof(signed_foo_t)*CHAR_BIT-1 <= IMAX_BITS(LONG_MAX)) ...

However, that picks the int256_t branch if a long is the same size
as signed_foo_t and can contain it, but both have padding bits.
--
Hallvard
Antoine Leca
2005-08-08 07:25:48 UTC
Permalink
En <news:***@g44g2000cwa.googlegroups.com>,
"algrant"@... va escriure:
<About [u]intmax_t>
Post by a***@myrealbox.com
Can you give sample code for such a reasonable use?
You cannot write C99 preprocessor without it.
I know there is no requirement for the C preprocessor to be written in C,
but the majority of them are.
Post by a***@myrealbox.com
How would the programmer encounter such an arbitrary type?
It can't be the result of a promotion, nor the result of a
standard library function.
We do not have the same definition for standard library function then. I
found 6 of them, plus any variation of the *scanf() functions using the
SCN?MAX specifiers.
Post by a***@myrealbox.com
If the implementation is then forced to define uintmax_t as
256 bits then it's constraining all users of uintmax_t to
take that performance hit - which makes it very much less
useful, hardly more useful than a suitably sized byte array.
If you feel a need to use intmax_t and you are hurt by the possible
performance problem, yes you are in trouble, because this means your target
audience (architecture × expected performance) does not allow you to use
maximally portable code; and yes you probably would have to lower your
portability expectations.

If you feel the same need, but you did _not_ expect the performance problem,
I should say there is misunderstanding of the usefulness of intmax_t
instead.


Antoine
k***@wizard.net
2005-07-28 16:35:58 UTC
Permalink
Post by jacob navia
A customer has asked me to add 128 bit integers to the 64 bit
version of my compiler system (lcc-win64).
After developing the assembly procedures, I have several
1) How should I name this stuff?
long long long ???
__int128 ?
int128 ?
It should not be called 'long long long'; 'long long' was enough of an
syntactic abomination, and <stdint.h> provides a alternative mechanism
that means we don't ever need to compound the error.
The identifier int128 intrudes on the namespace reserved for users;
don't use it. The identifier __int128 is reserved to the
implementation, and should be fine.

You should create all of the appropriate typedefs in <stdint.h>, and
the corresponding macros in <inttypes.h>. You should encourage your
customers to use those typedefs after checking whether or not the
corresponding macros have been defined. Don't even tell them about
__int128; it's purely an internal matter, and you should discourage
them from even thinking about it.
Post by jacob navia
2) How would this integers get printed with printf?
"%llld" ?
"%I128d" ?
Your customers should use PRId128, PRIdLEAST128, PRIdFAST128, or
PRIdMAX, as appropriate. What those macros expand to is up to you. You
can choose any length modifier other than the ones specified in
7.19.6.1p7, so long as it doesn't interfere with correctly parsing a
format string for which the length modifier is left unspecified (which
means you also cannot conflict with conversion specifiers, and you
can't use anything that would look like additional digits at the end of
precision specification). As with __int128, don't bother documenting
your chosen length modifier; encourage your customers to rely upon the
<inttypes.h> format macros.
Post by jacob navia
3) Should I supply definitions for it in inttypes.h, and in
stdint.h ?
Yes.
Post by jacob navia
4) What other implications can this new type have? I would have
loved to use long long for this, long for 64 bit, int for 32
bits, etc. But this is not possible for compatibility reasons.
There is too much software there that assumes long long is 64 bits,
not 128.
Which is precisely why the stdint.h and inttypes.h interface is a
better solution than "long long" was.
Keith Thompson
2005-07-28 18:37:54 UTC
Permalink
Post by jacob navia
A customer has asked me to add 128 bit integers to the 64 bit
version of my compiler system (lcc-win64).
After developing the assembly procedures, I have several
1) How should I name this stuff?
long long long ???
__int128 ?
int128 ?
2) How would this integers get printed with printf?
"%llld" ?
"%I128d" ?
3) Should I supply definitions for it in inttypes.h, and in
stdint.h ?
4) What other implications can this new type have? I would have
loved to use long long for this, long for 64 bit, int for 32
bits, etc. But this is not possible for compatibility reasons.
There is too much software there that assumes long long is 64 bits,
not 128.
They should be _extended integer types_, as defined in C99 6.2.5.

(I presume you're providing signed and unsigned versions; you didn't
mention that.)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Douglas A. Gwyn
2005-07-28 23:02:16 UTC
Permalink
Post by jacob navia
1) How should I name this stuff?
long long long ???
__int128 ?
int128 ?
Only the second is allowed, for conforming implementations.
Post by jacob navia
2) How would this integers get printed with printf?
"%llld" ?
"%I128d" ?
%I... is okay.
Post by jacob navia
3) Should I supply definitions for it in inttypes.h, and in
stdint.h ?
Absolutely. *All* supported integer types are supposed
to be entered in those headers. It has the advantage
of providing more portable names to get at the format
specifiers, also.
Post by jacob navia
4) What other implications can this new type have? I would have
loved to use long long for this, long for 64 bit, int for 32
bits, etc. But this is not possible for compatibility reasons.
There is too much software there that assumes long long is 64 bits,
not 128.
Really? That's scary. One would think that the lesson
would have been learned by now.

Anyway, it's what C99 calls an "extended integer type",
and you should check the standard to see how these fit
in with other integer types.
Antoine Leca
2005-08-08 07:56:28 UTC
Permalink
Post by jacob navia
A customer has asked me to add 128 bit integers
1) How should I name this stuff?
As far as I understand it, __int128 would be the logic used by the MS guys,
at least when they designed the current scheme (about 10 years ago.)

You might check with them.
Post by jacob navia
2) How would this integers get printed with printf?
"%I128d" ?
Again, the MS logic would command "I128" as length modifier.
Post by jacob navia
4) What other implications can this new type have?
[u]intmax_t should take it in account. This means the preprocessor would as
well, and a few headers also.
And this in turn might need a general check about buffer sizes all over the
library, particularly those parts that deal with integer-to-string
conversions.
Post by jacob navia
5) The string --> 128 bit integer procedure should be
strtolll ?
strtoi128 ?
strto128 ?
These names are reserved to future standardization (7.26).
However, I guess something along the lines of _strtoi128(), at least as the
*published* symbol, is probably better (less possible impact with already
existing code to be linked with your library), even if you also provide an
alias/weak symbol more easy to use.

Also, according to the existing pattern for [u]intmax_t, you might want to
provide a way to extract the absolute value (perhaps _i128abs()) and the
divisor+modulus pair (perhaps _i128div(), returning _i128div_t); along with
the obvious [_]strtou128(), [_]wcstoi128(), and [_]wcstou128().


Antoine
Thad Smith
2005-08-11 16:43:09 UTC
Permalink
Post by Antoine Leca
Post by jacob navia
5) The string --> 128 bit integer procedure should be
strtolll ?
strtoi128 ?
strto128 ?
These names are reserved to future standardization (7.26).
However, I guess something along the lines of _strtoi128(), at least as the
*published* symbol, is probably better (less possible impact with already
existing code to be linked with your library), even if you also provide an
alias/weak symbol more easy to use.
In a case such as strtoi128, where a clear extension to the existing
standard would give the semantics, I wouldn't lose sleep over the
implementor using strtoi128. The conservative approach, as you
suggest, is to assign a name in the implementor's namespace, but then
define a separate implementor header file which would provide aliases
using the common names. I consider using non-standard implementation
namespace identifiers (leading underscores) in user code ugly. For
such extensions I would rather include an implementation header,
thereby giving the implementation permission for limited intrusion
into user namespace.

Thad
Antoine Leca
2005-08-12 13:35:16 UTC
Permalink
Post by Antoine Leca
Post by jacob navia
5) The string --> 128 bit integer procedure should be
strtolll ?
strtoi128 ?
strto128 ?
These names are reserved to future standardization (7.26).
However, I guess something along the lines of _strtoi128(), at least
as the *published* symbol, is probably better (less possible impact
with already existing code to be linked with your library), even if
you also provide an alias/weak symbol more easy to use.
I consider using non-standard implementation namespace identifiers
(leading underscores) in user code ugly.
I believe I was not clear enough. I actually agree totally with your point
above (and I have big grief against a known vendor to require this much too
often in a 1990 "reform" of its implementation).

When I spoke about "publishing", I was referring to the name as known to the
linker. When it comes to which form of compiler magic is used to step from
strtoi128 (as written in the user code) to the _strtoi128 linker symbol in
the reserved namespace (as copied into the exec symbol table), I am
completely neutral.


Antoine
fabien carpignano
2023-04-05 20:30:35 UTC
Permalink
Post by jacob navia
A customer has asked me to add 128 bit integers to the 64 bit
version of my compiler system (lcc-win64).
After developing the assembly procedures, I have several
1) How should I name this stuff?
long long long ???
__int128 ?
int128 ?
2) How would this integers get printed with printf?
"%llld" ?
"%I128d" ?
3) Should I supply definitions for it in inttypes.h, and in
stdint.h ?
4) What other implications can this new type have? I would have
loved to use long long for this, long for 64 bit, int for 32
bits, etc. But this is not possible for compatibility reasons.
There is too much software there that assumes long long is 64 bits,
not 128.
jacob
http://www.cs.virginia.edu:/~lcc-win32
x64-128 pour inltel tu la deja 12 et 13 genertion mai il faux changet larchitecture paur amd x64_128
Arnold Ziffel
2023-04-07 01:12:48 UTC
Permalink
x64-128 pour inltel tu la deja 12 et 13 genertion mai il faux changet
larchitecture paur amd x64_128
Could you please write in English?
--
You cannot tame a tiger by pulling but one of his teeth.
Keith Thompson
2023-04-07 04:59:33 UTC
Permalink
Post by Arnold Ziffel
x64-128 pour inltel tu la deja 12 et 13 genertion mai il faux changet
larchitecture paur amd x64_128
Could you please write in English?
When replying to an article from 18 years ago?
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */
Arnold Ziffel
2023-04-08 00:36:51 UTC
Permalink
Post by Keith Thompson
Post by Arnold Ziffel
x64-128 pour inltel tu la deja 12 et 13 genertion mai il faux changet
larchitecture paur amd x64_128
Could you please write in English?
When replying to an article from 18 years ago?
Even then ;)
--
A complex system that works is invariably found to have evolved from a
more simple system that worked.
Loading...