Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

WTF is #define SIZE_MAX ((size_t)-1) ?

762 views
Skip to first unread message

pedr...@lycos.com

unread,
Sep 24, 2018, 6:46:22 AM9/24/18
to
I thought size_t means an unsigned integer (at least 16 bits), so how
can you use it with -1?

If found this when looking through memory.c, in libgfortran after I got
an xmallocarray error message, and trying to see what triggered the
particular error message. It involves SIZE_MAX as below

void *
xmallocarray (size_t nmemb, size_t size)
{
void *p;

if (!nmemb || !size)
size = nmemb = 1;
#define HALF_SIZE_T (((size_t) 1) << (__CHAR_BIT__ * sizeof (size_t) / 2))
else if (__builtin_expect ((nmemb | size) >= HALF_SIZE_T, 0)
&& nmemb > SIZE_MAX / size)
{
errno = ENOMEM;
os_error ("Integer overflow in xmallocarray");
}

p = malloc (nmemb * size);

if (!p)
os_error ("Memory allocation failed in xmallocarray");

return p;
}

Bart

unread,
Sep 24, 2018, 7:34:30 AM9/24/18
to
On 24/09/2018 11:46, pedr...@lycos.com wrote:
> I thought size_t means an unsigned integer (at least 16 bits), so how
> can you use it with -1?

-1 is usually a bit-patterns of all 1s.

Which is also the same bit-pattern you get with any maximum unsigned value.

So for 16 bits, -1 is 1111111111111111, and so is 65535. Same with 32
and 64 bits (with sequences of 32 and 64 1s).

It was an easy way to get SIZE_MAX without needing to know how many bits
it had.

Think of it as ((size_t)(0u-1u)) which is slightly better defined.

--
bart

Öö Tiib

unread,
Sep 24, 2018, 7:42:38 AM9/24/18
to
On Monday, 24 September 2018 13:46:22 UTC+3, Pedro V wrote:
> I thought size_t means an unsigned integer (at least 16 bits), so how
> can you use it with -1?

You can use because unsigned follows modular arithmetic. Sine size_t is
unsigned type the (size_t)-1 is defined to be largest value of that type.

Rick C. Hodgin

unread,
Sep 24, 2018, 8:57:53 AM9/24/18
to
On 9/24/2018 6:46 AM, pedr...@lycos.com wrote:
> [snip]

Pedro, using the kind of language you put in this header, to a group
you don't know ... what does it reveal about your character? About
how you regard other people in your life?

There's another way to go that places a greater respect and emphasis
on people, on meeting them where they are rather than just asserting
yourself atop them by some brute force.

Remember the people you're writing to are people, and hold yourself
in a proper regard toward them, holding them higher than yourself.
It is the right thing to do. It will bring peace to your soul. And
it will fill your heart with love and joy, as per God's design.

--
Rick C. Hodgin

PS -- I tried to send this message privately, but the posted
pedr...@lycos.com bounced as an invalid email address.

mark.b...@gmail.com

unread,
Sep 24, 2018, 9:21:48 AM9/24/18
to
On Monday, 24 September 2018 13:57:53 UTC+1, Rick C. Hodgin wrote:
[A lecture on good manners, based on the use of "WTF" in the subject]
You are in no position to talk of respect and manners, Rick.

Ben Bacarisse

unread,
Sep 24, 2018, 9:25:32 AM9/24/18
to
pedr...@lycos.com writes:

> I thought size_t means an unsigned integer (at least 16 bits), so how
> can you use it with -1?

Copying from the subject:

#define SIZE_MAX ((size_t)-1)

A signed integer value is converted to an unsigned type by subtracting
(repeatedly if necessary) one more than the maximum value of that type.
This is "reduction modulo 2**w" where w is the number of value bits in
the unsigned type. As a result, when T is an unsigned integer type,
(T)-1 is the maximum value that T can represent.

I sounds complicated but very often it's a no-op or nothing more than
a direct copying of bits. Sometimes an 'and' with a mask might be
needed.

C99 and later define SIZE_MAX in a header called stdint.h.

<snip>
--
Ben.

Rick C. Hodgin

unread,
Sep 24, 2018, 9:50:46 AM9/24/18
to
On 9/24/2018 9:21 AM, mark.b...@gmail.com wrote:
> You are in no position to talk of respect and manners, Rick.

How so, Mark?

--
Rick C. Hodgin

Ben Bacarisse

unread,
Sep 24, 2018, 10:08:24 AM9/24/18
to
Bart <b...@freeuk.com> writes:

> On 24/09/2018 11:46, pedr...@lycos.com wrote:
>> I thought size_t means an unsigned integer (at least 16 bits), so how
>> can you use it with -1?
>
> -1 is usually a bit-patterns of all 1s.

But it may not be. Even when it isn't (size_t)-1 will work because the
definition of what that means is based on values not representations.

The representation can affect how efficient the operation is, but not
what it means.

> Which is also the same bit-pattern you get with any maximum unsigned value.
>
> So for 16 bits, -1 is 1111111111111111, and so is 65535. Same with 32
> and 64 bits (with sequences of 32 and 64 1s).
>
> It was an easy way to get SIZE_MAX without needing to know how many
> bits it had.
>
> Think of it as ((size_t)(0u-1u)) which is slightly better defined.

No, they are both equally well-defined, but (size_t)-1 is correct
whereas (size_t)(0u-1u) is not. (It goes wrong when size_t is wider
than unsigned int, which is not an uncommon situation.)

I don't want to discourage anyone from giving advice but when you have
explicitly stated that you don't want to learn what you think of as C's
crazy rules, it seems odd that you choose to.

--
Ben.

Dan Purgert

unread,
Sep 24, 2018, 10:53:28 AM9/24/18
to
WTF does using 'WTF' in a Usenet post trigger lectu... oh, wait, right,
that Rick character's the guy who posted all those christian
brainwashing things isn't he?


--
|_|O|_| Registered Linux user #585947
|_|_|O| Github: https://github.com/dpurgert
|O|O|O| PGP: 05CA 9A50 3F2E 1335 4DC5 4AEE 8E11 DDF3 1279 A281

guinne...@gmail.com

unread,
Sep 24, 2018, 10:58:11 AM9/24/18
to
On Monday, 24 September 2018 13:57:53 UTC+1, Rick C. Hodgin wrote:
> On 9/24/2018 6:46 AM, pedr...@lycos.com wrote:
> > [snip]
>
> Pedro, using the kind of language you put in this header, to a group
> you don't know ... what does it reveal about your character? About
> how you regard other people in your life?

What the heck is wrong with somebody using the abbreviated form for
"what the flip"?

<snip preachy twaddle>

Rick C. Hodgin

unread,
Sep 24, 2018, 11:00:17 AM9/24/18
to
On Monday, September 24, 2018 at 10:53:28 AM UTC-4, Dan Purgert wrote:
> that Rick character's the guy who posted all those christian
> brainwashing things isn't he?

Why do you think I post those things, Dan? Why do I want you to
ask forgiveness for your sin and gain eternal life? Why do I
want you to be in Heaven with God in paradise set free from this
world and all the hate and war and death here?

Is it for my bank account? So I can add another convert notch
to my belt? Or is it because I care about you, recognize you do
have sin, and know the way out of sin's damnation of our soul?

Don't just leave it at "Christian brainwashing" ... investigate
for yourself why I might post these things when there is so much
blow-back against it. It's not for nothing. And it's not for
selfish reasons. It's because I care about you and want the
best for your future.

--
Rick C. Hodgin

james...@alumni.caltech.edu

unread,
Sep 24, 2018, 11:11:23 AM9/24/18
to
On Monday, September 24, 2018 at 9:50:46 AM UTC-4, Rick C. Hodgin wrote:
> On 9/24/2018 9:21 AM, mark.b...@gmail.com wrote:
> > You are in no position to talk of respect and manners, Rick.
>
> How so, Mark?

You have no respect for topicality, and even if the off-topic "truths"
that you were preaching were exactly as true at you think they are, and
even if the importance you attach to those "facts" was a matter of
objective truth rather than subjective opinion, it would still be
extremely rude to post such messages in a newsgroup devoted to a
different subject.

mark.b...@gmail.com

unread,
Sep 24, 2018, 11:16:05 AM9/24/18
to
I couldn't have put it better myself. Thank you James.

mark.b...@gmail.com

unread,
Sep 24, 2018, 11:18:14 AM9/24/18
to
On Monday, 24 September 2018 16:00:17 UTC+1, Rick C. Hodgin wrote:
> On Monday, September 24, 2018 at 10:53:28 AM UTC-4, Dan Purgert wrote:
> > that Rick character's the guy who posted all those christian
> > brainwashing things isn't he?
>
> Why do you think I post those things,...?

Because you are a rude, self-important, self-righteous, deluded religious
bigot. Next question.

Bart

unread,
Sep 24, 2018, 11:18:57 AM9/24/18
to
On 24/09/2018 15:08, Ben Bacarisse wrote:
> Bart <b...@freeuk.com> writes:
>
>> On 24/09/2018 11:46, pedr...@lycos.com wrote:
>>> I thought size_t means an unsigned integer (at least 16 bits), so how
>>> can you use it with -1?
>>
>> -1 is usually a bit-patterns of all 1s.
>
> But it may not be.

What are the chances of that?

(I remember an interview question for a student placement around '77
which revolved around whether -1 had an all 1s representation. This
would have been in the days when there were more wacky architectures
about. I made that assumption, and in the end was offered the job.

Maybe I should have been smart and started talking about ones complement
and signed magnitude and the rest, and maybe I would still have got the
offer. Or maybe not.

Since then, I don't think any of the 9 or 10 architectures I've coded
for (and a few more I've studied) would have had anything other than an
all 1s representation of -1.)

>> Think of it as ((size_t)(0u-1u)) which is slightly better defined.
>
> No, they are both equally well-defined, but (size_t)-1 is correct
> whereas (size_t)(0u-1u) is not. (It goes wrong when size_t is wider
> than unsigned int, which is not an uncommon situation.)

I said to think of it like that, ie. as subtracting unsigned 1 from
unsigned 0, since the wraparound characteristics are easier to
appreciate. Maybe the example would have been better as (size_t)0-(size_t)1.

What I was trying to get across is that if you subtract 1 from 0 (even
with pen and paper if doing it in binary), you will get an all ones
pattern, which, with a given bitwidth, is /usually/ -1 if interpreted as
signed, and as the maximum value when interpreted as unsigned.

(With pen and paper, if doing it in decimal, you also make the
interesting discovery that -1 can be represented as an infinite sequence
of 9s, ie. "....999". Negative numbers with denoted with "-", really
signed magnitude, aren't needed after all!)

> I don't want to discourage anyone from giving advice but when you have
> explicitly stated that you don't want to learn what you think of as C's
> crazy rules, it seems odd that you choose to.

Well I read your reply to the OP, and I couldn't make head or tail of
it, not even on a second reading. Sometimes you want to keep those crazy
rules at bay as much as possible and just try and make practical common
sense work.


--
bart

James Kuyper

unread,
Sep 24, 2018, 11:39:57 AM9/24/18
to
On 09/24/2018 09:25 AM, Ben Bacarisse wrote:
> pedr...@lycos.com writes:
>
>> I thought size_t means an unsigned integer (at least 16 bits), so how
>> can you use it with -1?
>
> Copying from the subject:
>
> #define SIZE_MAX ((size_t)-1)
>
> A signed integer value is converted to an unsigned type by subtracting

or adding, depending upon the value. Which is important in this
particular case, because it is indeed addition that is needed, not
subtraction.

> (repeatedly if necessary) one more than the maximum value of that type.

Whenever I quote this rule and apply it, I like to point out exactly how
many times that value needs to be added or subtracted, to make the
explanation more concrete. In this particular case, it needs to be added
exactly once.

Scott Lurndal

unread,
Sep 24, 2018, 11:42:51 AM9/24/18
to
Bart <b...@freeuk.com> writes:
.
>
>Since then, I don't think any of the 9 or 10 architectures I've coded
>for (and a few more I've studied) would have had anything other than an
>all 1s representation of -1.)

I worked for several years (on the operating system) with an architecture
where the value -1 could be represented many different ways (albeit with
the caveat that the first nibble had the value 0b1101, the last nibble had
the value 0b0001 and any intervening nibbles had the value 0b0000 (big-endian)).

In no case was it ever represented as all-ones.

So, 0xd0000001, 0xd1, 0xd01 et alia all represent the decimal value -1.

If you consider it to be analogous to a "signed magnitude" format, you'll be close enough.

For various reasons, that architecture was not a good target for a C compiler. COBOL
on the other hand was a very natural fit.

http://vseries.lurndal.org/doku.php?id=architecture

Spiros Bousbouras

unread,
Sep 24, 2018, 12:09:54 PM9/24/18
to
On Mon, 24 Sep 2018 11:39:45 -0400
James Kuyper <james...@alumni.caltech.edu> wrote:
> On 09/24/2018 09:25 AM, Ben Bacarisse wrote:
> > pedr...@lycos.com writes:
> >
> >> I thought size_t means an unsigned integer (at least 16 bits), so how
> >> can you use it with -1?
> >
> > Copying from the subject:
> >
> > #define SIZE_MAX ((size_t)-1)
> >
> > A signed integer value is converted to an unsigned type by subtracting
>
> or adding, depending upon the value. Which is important in this
> particular case, because it is indeed addition that is needed, not
> subtraction.
>
> > (repeatedly if necessary) one more than the maximum value of that type.
>
> Whenever I quote this rule and apply it, I like to point out exactly how
> many times that value needs to be added or subtracted, to make the
> explanation more concrete. In this particular case, it needs to be added
> exactly once.

The description of this rule in the standard is unnecessarily convoluted and
unmathematical. A better way would be the following :

If N is the maximum value which can be stored in an integer unsigned
type T , then the converted to type T integer value M is the unique
number M' such that 0 <= M' <= N and M'-M divisible by N+1 .

In every situation I have ever encountered , the above rule was what was
needed in order to reason on whether the conversion was what I wanted whereas
thinking in terms of repeated additions or subtractions would be an extra
step just to make sure that the rule holds.

So to convert -1 to type T we observe that 0 <= N <= N and N-(-1) = N+1
which is divisible by N+1 therefore the converted value is N .

> > This is "reduction modulo 2**w" where w is the number of value bits in
> > the unsigned type. As a result, when T is an unsigned integer type,
> > (T)-1 is the maximum value that T can represent.

This is another way of putting it but I don't think it helps understanding
by bringing into the picture the number of value bits. The number of value
bits determines N and once you have N then you can express the rule without
caring how N is obtained.

--
vlaho.ninja/prog

Rick C. Hodgin

unread,
Sep 24, 2018, 12:23:57 PM9/24/18
to
There's a teaching there you miss, that Jesus is required to be
first in our lives, and then we do the things we do second, in sub-
jection to Him, serving Him in what we do, being obedient to His
teachings first, adjusting /ALL/ our goals to meet His needs for
our lives.

Why? Because of who He is: truth, righteousness, holiness in the
flesh, in the spirit, upholding all things everywhere by the power
of His word.

I want you all posting abour C programming interests ... but I teach
you all that you need to do it unto the Lord first.

It is a true and proper teaching, backed up wholly by scripture,
and it is right by every standard.

I teach these things here because no one else is, and there is rampant
aversion to His ways, and rampant adherence to the dead-end ways of
this sinful world.

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 24, 2018, 12:26:33 PM9/24/18
to
After the rapture, when you are left behind to go through the painful
years of the Great Tribulation, remember these things I tried to teach
you. Just as they could save you now, they'll be able to save you then,
but it will be much much much harder then.

--
Rick C. Hodgin

james...@alumni.caltech.edu

unread,
Sep 24, 2018, 12:59:12 PM9/24/18
to
On Monday, September 24, 2018 at 12:23:57 PM UTC-4, Rick C. Hodgin wrote:
> On Monday, September 24, 2018 at 11:11:23 AM UTC-4, james...@alumni.caltech.edu wrote:
> > On Monday, September 24, 2018 at 9:50:46 AM UTC-4, Rick C. Hodgin wrote:
> > > On 9/24/2018 9:21 AM, mark.b...@gmail.com wrote:
> > > > You are in no position to talk of respect and manners, Rick.
> > >
> > > How so, Mark?
> >
> > You have no respect for topicality, and even if the off-topic "truths"
> > that you were preaching were exactly as true at you think they are, and
> > even if the importance you attach to those "facts" was a matter of
> > objective truth rather than subjective opinion, it would still be
> > extremely rude to post such messages in a newsgroup devoted to a
> > different subject.
>
> There's a teaching there you miss, that Jesus is required to be

What makes you think I missed it? I've lived all my life in one of the more solidly Christian countries in the world - I've been subjected to that teaching all my life. I rejected it as invalid based upon a lack of supporting evidence - I did not in any sense miss it.

> first in our lives, and then we do the things we do second, in sub-
> jection to Him, serving Him in what we do, being obedient to His
> teachings first, adjusting /ALL/ our goals to meet His needs for
> our lives.

Believing that doesn't make it any less rude to impose your beliefs on the matter on people who don't share them - it just motivates you more strongly to be rude. If you truly believe this is justified behavior - embrace it. Loudly proclaim "Jesus entitles me to be rude to non-believers." It's somewhat nicer that believing He entitles you to kill non-believers, which some of your co-belivers have argued. But please recognize that it is indeed rude.

Rick C. Hodgin

unread,
Sep 24, 2018, 1:09:32 PM9/24/18
to
On Monday, September 24, 2018 at 12:59:12 PM UTC-4, james...@alumni.caltech.edu wrote:
> On Monday, September 24, 2018 at 12:23:57 PM UTC-4, Rick C. Hodgin wrote:
> > There's a teaching there you miss, that Jesus is required to be
>
> What makes you think I missed it? I've lived all my life in one of the more solidly Christian countries in the world - I've been subjected to that teaching all my life. I rejected it as invalid based upon a lack of supporting evidence - I did not in any sense miss it.

You missed it. Many people do. Many people reject it for whatever
reason.

The message isn't for them. It's for those who are being saved.

Jesus commands us to go forth and teach. I'll listen to Him ahead
of you, James, especially since you've rejected Him to your eternal
peril. Yours would be the last advice I would take, or opinion I
would listen to.

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 24, 2018, 1:14:09 PM9/24/18
to
On Monday, September 24, 2018 at 1:09:32 PM UTC-4, Rick C. Hodgin wrote:
> Jesus commands us to go forth and teach. I'll listen to Him ahead
> of you, James, especially since you've rejected Him to your eternal
> peril. Yours would be the last advice I would take, or opinion I
> would listen to.

... on this matter.

--
Rick C. Hodgin

Keith Thompson

unread,
Sep 24, 2018, 1:55:07 PM9/24/18
to
james...@alumni.caltech.edu writes:
> On Monday, September 24, 2018 at 12:23:57 PM UTC-4, Rick C. Hodgin wrote:
[...]
>> There's a teaching there you miss, that Jesus is required to be
>
> What makes you think I missed it?
[...]

Let me remind everyone who wants to argue religion with Rick that he
posts using a valid email address. No need to discuss it here.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Bart

unread,
Sep 24, 2018, 3:14:27 PM9/24/18
to
That doesn't sound like a normal 'binary' computer, even if the bytes
and 4-bit 'digits' it uses are built on top of binary bits.

In the case of digits, the possible bit patterns go from 0000 to 1111 of
unsigned values. There is no interpretation of those as a 4-bit signed
value at all, so that doesn't come into it.

In the case of bytes, which presumably go from 00000000 to 11111111, it
says they are usually unsigned. But it also mentions that certain
instructions treat those as signed, although it doesn't say what scheme
it uses.

So we don't know what pattern a signed byte representing -1 would have,
except that twos complement would again have it as 11111111.

What I'm saying is that signed magnitude (using a special symbol for
negative, such as "-" on paper), and twos complement (which I believe
works in any base) are natural ways of representing signed numbers

And it is the latter that is dominant with computers.

That doesn't stop people design designing varieties of weird systems
that are incompatible with anything else, or with languages that expect
certain requirements to be met. Like in your link.


--
bart

Scott Lurndal

unread,
Sep 24, 2018, 4:26:24 PM9/24/18
to
Bart <b...@freeuk.com> writes:
>On 24/09/2018 16:42, Scott Lurndal wrote:
>> Bart <b...@freeuk.com> writes:
>> .
>>>
>>> Since then, I don't think any of the 9 or 10 architectures I've coded
>>> for (and a few more I've studied) would have had anything other than an
>>> all 1s representation of -1.)
>>
>> I worked for several years (on the operating system) with an architecture
>> where the value -1 could be represented many different ways (albeit with
>> the caveat that the first nibble had the value 0b1101, the last nibble had
>> the value 0b0001 and any intervening nibbles had the value 0b0000 (big-endian)).
>>
>> In no case was it ever represented as all-ones.
>>
>> So, 0xd0000001, 0xd1, 0xd01 et alia all represent the decimal value -1.
>>
>> If you consider it to be analogous to a "signed magnitude" format, you'll be close enough.
>>
>> For various reasons, that architecture was not a good target for a C compiler. COBOL
>> on the other hand was a very natural fit.
>>
>> http://vseries.lurndal.org/doku.php?id=architecture
>>
>That doesn't sound like a normal 'binary' computer, even if the bytes
>and 4-bit 'digits' it uses are built on top of binary bits.

I don't recall every claiming that it was a normal 'binary' computer.

>
>In the case of digits, the possible bit patterns go from 0000 to 1111 of
>unsigned values. There is no interpretation of those as a 4-bit signed
>value at all, so that doesn't come into it.

Of course they're interpreted; the values range from zero to fifteen.

>
>In the case of bytes, which presumably go from 00000000 to 11111111, it
>says they are usually unsigned. But it also mentions that certain
>instructions treat those as signed, although it doesn't say what scheme
>it uses.

If you read the instruction descriptions, it does. Basically it preserves
the sign indication in the first EBCDIC byte zone digit. See, for instance,
<http://vseries.lurndal.org/doku.php?id=instructions:mva> under 'UA to SN'
and 'SN to UA' moves.

//
// If the source field was UA and the destination field is SN we
// extract and normalize the sign from the zone digit of the first
// byte of the source field.
//
if (types == UASN) {
a_sign = (gethex(a_addr, 1) == 0xd)?0xd:0xc;
p_mp->putdigit(b_addr-1, a_sign);
}

//
// If the source field was SN and the destination field is UA we
// store the sign in the zone digit of the first byte of the
// destination field.
//
if (types == SNUA) {
p_mp->putdigit(b_addr, a_sign);
}


>
>So we don't know what pattern a signed byte representing -1 would have,
>except that twos complement would again have it as 11111111.

There is no "signed byte".

>
>What I'm saying is that signed magnitude (using a special symbol for
>negative, such as "-" on paper), and twos complement (which I believe
>works in any base) are natural ways of representing signed numbers

To you, perhaps. However, very few of the first three generations
of computing systems used twos complement.


>That doesn't stop people design designing varieties of weird systems
>that are incompatible with anything else, or with languages that expect
>certain requirements to be met. Like in your link.

That "weird" system processed ATM and teller transactions for hundreds
of financial institutions over six processor generations (starting in
the 1950's) for over fifty years. The larger systems sold for $1.5 million
USD in the 1980s'.

David Brown

unread,
Sep 24, 2018, 4:51:15 PM9/24/18
to
On 24/09/18 17:18, Bart wrote:
> On 24/09/2018 15:08, Ben Bacarisse wrote:
>> Bart <b...@freeuk.com> writes:
>>
>>> On 24/09/2018 11:46, pedr...@lycos.com wrote:
>>>> I thought size_t means an unsigned integer (at least 16 bits), so how
>>>> can you use it with -1?
>>>
>>> -1 is usually a bit-patterns of all 1s.
>>
>> But it may not be.
>
> What are the chances of that?
>
> (I remember an interview question for a student placement around '77
> which revolved around whether -1 had an all 1s representation. This
> would have been in the days when there were more wacky architectures
> about. I made that assumption, and in the end was offered the job.
>
> Maybe I should have been smart and started talking about ones complement
> and signed magnitude and the rest, and maybe I would still have got the
> offer. Or maybe not.
>
> Since then, I don't think any of the 9 or 10 architectures I've coded
> for (and a few more I've studied) would have had anything other than an
> all 1s representation of -1.)
>

There have never been many systems that had something other than all 1's
for -1, but there have been a few. You are not likely to come across
them, especially in modern C programming. (I have worked with
programming language implementations where -1 had a representation other
than all 1's, but it was not C.)

I would say "-1 is usually a bit-pattern of all 1's" is an entirely
reasonable thing to write. However, it is also entirely irrelevant to
this situation.

>>> Think of it as ((size_t)(0u-1u)) which is slightly better defined.
>>
>> No, they are both equally well-defined, but (size_t)-1 is correct
>> whereas (size_t)(0u-1u) is not.  (It goes wrong when size_t is wider
>> than unsigned int, which is not an uncommon situation.)
>
> I said to think of it like that, ie. as subtracting unsigned 1 from
> unsigned 0, since the wraparound characteristics are easier to
> appreciate. Maybe the example would have been better as
> (size_t)0-(size_t)1.

I can't see how that would help anyone in their understanding of
"(size_t) -1". This involves explaining how negative signed integers
get converted to unsigned types - while "(size_t) 0 - (size_t) 1"
involves how overflow of arithmetic on unsigned types is defined. These
are two different concepts.

They are, however, equally well defined - neither is "slightly better
defined".

>
> What I was trying to get across is that if you subtract 1 from 0 (even
> with pen and paper if doing it in binary), you will get an all ones
> pattern, which, with a given bitwidth, is /usually/ -1 if interpreted as
> signed, and as the maximum value when interpreted as unsigned.
>

That is true - and it might have been useful to explain things that way,
if it had been relevant (the all 1's nature of (size_t) -1 in typical
implementations is not actually relevant).

> (With pen and paper, if doing it in decimal, you also make the
> interesting discovery that -1 can be represented as an infinite sequence
> of 9s, ie. "....999". Negative numbers with denoted with "-", really
> signed magnitude, aren't needed after all!)

That is just nonsense.

>
>> I don't want to discourage anyone from giving advice but when you have
>> explicitly stated that you don't want to learn what you think of as C's
>> crazy rules, it seems odd that you choose to.
>
> Well I read your reply to the OP, and I couldn't make head or tail of
> it, not even on a second reading. Sometimes you want to keep those crazy
> rules at bay as much as possible and just try and make practical common
> sense work.
>
Try again, and if it still doesn't make sense, ask someone about the
parts you have trouble with. If you don't understand something, ask -
don't try to add your own alternative confusions as an answer to someone
else's question.

Kenny McCormack

unread,
Sep 24, 2018, 5:53:36 PM9/24/18
to
In article <pobinq$ojh$1...@dont-email.me>,
David Brown <david...@hesbynett.no> wrote:
...
> Try again, and if it still doesn't make sense, ask someone about the
>parts you have trouble with. If you don't understand something, ask -
>don't try to add your own alternative confusions as an answer to someone
>else's question.
>

I don't know who is more sanctimonious - you or Rick.

No, just kidding. Rick has you beat. You need not worry.

--
Mike Huckabee has yet to consciously uncouple from Josh Duggar.

Bart

unread,
Sep 24, 2018, 6:08:06 PM9/24/18
to
On 24/09/2018 21:51, David Brown wrote:
> On 24/09/18 17:18, Bart wrote:

>> Since then, I don't think any of the 9 or 10 architectures I've coded
>> for (and a few more I've studied) would have had anything other than
>> an all 1s representation of -1.)
>
> There have never been many systems that had something other than all 1's
> for -1, but there have been a few.  You are not likely to come across
> them, especially in modern C programming.  (I have worked with
> programming language implementations where -1 had a representation other
> than all 1's, but it was not C.)

In software anyone can make up their own schemes. As a simple example,
they can choose to use floating point representation for integers, where
-1 might be stored as:

-100000000010000000000000000000000000000000000000000000000000000

in binary. And I use a big int library that uses signed-magnitude
decimals with 'digits' that go from 0 to 999999. -1 would be the two
32-bit words (1,1).

This is about common machine representations and languages that work
closely with such representations.

>> (With pen and paper, if doing it in decimal, you also make the
>> interesting discovery that -1 can be represented as an infinite
>> sequence of 9s, ie. "....999". Negative numbers with denoted with "-",
>> really signed magnitude, aren't needed after all!)
>
> That is just nonsense.

(It what way? If I add 1 to "...999" I get 0, just as I would adding 1
to -1.

If I multiply "...999" by itself I get "...0001", or +1, just as I get
if I square -1.

If I multiply it by 5 I get "...995", which if I add +5, gives me 0,
just as -5 would do.

So it all seems to work.

But having to have an infinite number of leading digits, or using a
fixed number with the left-most one designated a sign digit, is
inconvenient. Inside a computer however and using binary (and with a
fixed number of digits, not infinite), it is very helpful.)

>>
>>> I don't want to discourage anyone from giving advice but when you have
>>> explicitly stated that you don't want to learn what you think of as C's
>>> crazy rules, it seems odd that you choose to.
>>
>> Well I read your reply to the OP, and I couldn't make head or tail of
>> it, not even on a second reading. Sometimes you want to keep those
>> crazy rules at bay as much as possible and just try and make practical
>> common sense work.
>>
>  Try again, and if it still doesn't make sense, ask someone about the
> parts you have trouble with.

Here's the fast part:

"A signed integer value is converted to an unsigned type by subtracting
(repeatedly if necessary) one more than the maximum value of that type."

Assuming "that type" means the unsigned type we're trying to determine
the maximum value of, then that method for working out that value,
requires that you first know what that value is!

If someone is trying to work through that with pen and paper, then they
will need to know SIZE_MAX before they can determine SIZE_MAX.

> If you don't understand something, ask -
> don't try to add your own alternative confusions as an answer to someone
> else's question.

C doesn't have a monopoly on signed and unsigned representations of
binary integers. These same problems come up with any number of
languages, and outside languages too as they are among the fundamental
characteristics of nearly all computers.

That the byte pattern 11111111, is 255 or the maximum value of an
unsigned byte, if interpreted one way, or -1 if interpreted as signed -
for twos complement - has been very well known for decades. And is the
basis for using ((size_t)-1) since the -1 gives you as many ones as needed.



--
bart

Ben Bacarisse

unread,
Sep 24, 2018, 8:16:15 PM9/24/18
to
Bart <b...@freeuk.com> writes:

> On 24/09/2018 15:08, Ben Bacarisse wrote:
>> Bart <b...@freeuk.com> writes:
>>
>>> On 24/09/2018 11:46, pedr...@lycos.com wrote:
>>>> I thought size_t means an unsigned integer (at least 16 bits), so how
>>>> can you use it with -1?
>>>
>>> -1 is usually a bit-patterns of all 1s.
>>
>> But it may not be.
>
> What are the chances of that?

I don't know. Why do you care? The expression in question is defined
in terms of values so how likely any particular representation is is
beside the point. Unless you are going to discuss efficiency, but you
did not appear to be discussing that aspect.

>>> Think of it as ((size_t)(0u-1u)) which is slightly better defined.
>>
>> No, they are both equally well-defined, but (size_t)-1 is correct
>> whereas (size_t)(0u-1u) is not. (It goes wrong when size_t is wider
>> than unsigned int, which is not an uncommon situation.)
>
> I said to think of it like that,

No, you literally said "think of it as" which is much more literal than
"like". Anyway, even as an analogous expression "somewhat like" the
original, giving one that's wrong, for reasons that are directly
relevant to understanding the original, is obviously going to introduce
even more confusion.

> ie. as subtracting unsigned 1 from unsigned 0, since the wraparound
> characteristics are easier to appreciate.

It's not clear that is is easier to appreciate, though that will
probably depend on the OPs previous experience. I can see the value in
giving the OP lots of alternative explanations -- just keep clear of
writing C expressions that have quite different meaning. There is no
way that can be helpful.

> Maybe the example would have been better as (size_t)0-(size_t)1.

Yes, that has the advantage of being an equivalent expression. But some
people would (correctly) say that (size_t)0-(size_t)1 has the value -1
which, by the "usual arithmetic conversions" but be converted to
size_t. I.e. they might (correctly) conclude that to understand
(size_t)0-(size_t)1 one must understand (size_t)-1.

Some other people will be reminded of what they know about how most
modern computer do arithmetic "internally" and so they may be led to the
right answer that way withoug having to understand (size_t)-1 directly.
However, those people might come away with the idea that (size_t)-1 is
somehow linked to the internal representation used on the machine the
code executes on.

> What I was trying to get across is that if you subtract 1 from 0 (even
> with pen and paper if doing it in binary), you will get an all ones
> pattern, which, with a given bitwidth, is /usually/ -1 if interpreted
> as signed, and as the maximum value when interpreted as unsigned.

I can see what you are getting at but it's not obvious that subtraction
is a simpler notion that conversion. It all depends on past experience.
But your "binary odometer" analogy gives a false impression -- that the
result might be linked to the integer representation. For example, on
some legacy hardware, unsigned arithmetic is emulated using the floating
point unit. Even there (size_t)-1 must be SIZE_MAX even though the bit
representation of -1 and SIZE_MAX are very much unrelated.

Analogies can help, but there is no substitute for saying (eventually)
that (size_t)-1 must equal SIZE_MAX, regardless of how the arithmetic is
done at the bit level.

--
Ben.

Keith Thompson

unread,
Sep 24, 2018, 8:51:41 PM9/24/18
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:
> Bart <b...@freeuk.com> writes:
[...]
>> Maybe the example would have been better as (size_t)0-(size_t)1.
>
> Yes, that has the advantage of being an equivalent expression.

Not necessarily.

If size_t is narrower than int (let's say size_t is 16 bits and int is
32 bits), then the two operands of the "-" operator promote to (signed)
int. The result is of type int, and has the value -1.

You're not likely to encounter a system where size_t is narrower than
int, but this is yet another reason it's best to explain these things
the way they're defined by the standard (and if you don't understand
what the standard says, let others explain it).

Bart

unread,
Sep 24, 2018, 9:01:56 PM9/24/18
to
On 25/09/2018 01:16, Ben Bacarisse wrote:
> Bart <b...@freeuk.com> writes:

>> Maybe the example would have been better as (size_t)0-(size_t)1.
>
> Yes, that has the advantage of being an equivalent expression. But some
> people would (correctly) say that (size_t)0-(size_t)1 has the value -1
> which, by the "usual arithmetic conversions" but be converted to
> size_t. I.e. they might (correctly) conclude that to understand
> (size_t)0-(size_t)1 one must understand (size_t)-1.

The original confusion was in mixing up a negative value with an
unsigned type.

(size_t)0 and (size_t)1 are both unsigned (if anyone recognises that 0
and 1 happened to be signed, they will not see any problems in
converting those to unsigned).

So you have unsigned 1 being subtracted from unsigned 0.

> However, those people might come away with the idea that (size_t)-1 is
> somehow linked to the internal representation used on the machine the
> code executes on.

There has to be a link at some point otherwise you'd have to explain why
C, if it is supposed to be independent of any physical machine, is full
of power-of-two type widths.


> Analogies can help, but there is no substitute for saying (eventually)
> that (size_t)-1 must equal SIZE_MAX, regardless of how the arithmetic is
> done at the bit level.

I tend to come at these things from the other direction. I know how my
hardware works, and expect the HLL - especially a HLL which is famously
'close to the metal', supposedly - to support that operational model.

--
bart

Ben Bacarisse

unread,
Sep 24, 2018, 11:52:43 PM9/24/18
to
Bart <b...@freeuk.com> writes:

> On 25/09/2018 01:16, Ben Bacarisse wrote:
>> Bart <b...@freeuk.com> writes:
>
>>> Maybe the example would have been better as (size_t)0-(size_t)1.
>>
>> Yes, that has the advantage of being an equivalent expression. But some
>> people would (correctly) say that (size_t)0-(size_t)1 has the value -1
>> which, by the "usual arithmetic conversions" but be converted to
>> size_t. I.e. they might (correctly) conclude that to understand
>> (size_t)0-(size_t)1 one must understand (size_t)-1.
>
> The original confusion was in mixing up a negative value with an
> unsigned type.

Your re-write does not solve that unless the reader knows something that
you did not explain.

> (size_t)0 and (size_t)1 are both unsigned (if anyone recognises that 0
> and 1 happened to be signed, they will not see any problems in
> converting those to unsigned).
>
> So you have unsigned 1 being subtracted from unsigned 0.

(Better to say "an unsigned 1" because "unsigned" is an actual C type
and may not be the same type as size_t.)

The result of that subtraction is a mathematical value: -1. This value
is then converted to size_t because that's the type determined by the
usual arithmetic conversions (provided Keith's caveat does not apply).
This is how C defines (size_t)0-(size_t)1.

I.e. the way C explains your expression requires the reader to already
know what (size_t)-1 means.

Now the reader may know something about how machines do arithmetic, and
may know or guess what your are implying with this special "unsigned
subtraction". But then they may also think that implementation that use
different representations, like sign and magnitude, might have
(size_t)-1 != SIZE_MAX.

>> Analogies can help, but there is no substitute for saying (eventually)
>> that (size_t)-1 must equal SIZE_MAX, regardless of how the arithmetic is
>> done at the bit level.
>
> I tend to come at these things from the other direction.

Except you did not explain how this unsigned subtraction works -- that
crucial part was missing. Putting aside that 0u-1u was not the right
subtraction I don't recall you explaining how it works.

C defines 0u-1u to be -1, converted to unsigned. If you are going to
avoid explaining the original issue, you need to explain this special
subtraction that does give a mathematical negative number.

> I know how my hardware works, and expect the HLL - especially a HLL
> which is famously 'close to the metal', supposedly - to support that
> operational model.

It does, so there's no problem. It's not, however, limited to your
hardware because it's not defined in terms of that operational model.

--
Ben.

mark.b...@gmail.com

unread,
Sep 25, 2018, 4:00:58 AM9/25/18
to
On Monday, 24 September 2018 21:26:24 UTC+1, Scott Lurndal wrote:
> Bart <b...@freeuk.com> writes:

> >That doesn't sound like a normal 'binary' computer, even if the bytes
> >and 4-bit 'digits' it uses are built on top of binary bits.
>
> I don't recall every claiming that it was a normal 'binary' computer.

Well, in that case, it's irrelevant to any discussion with Bart. If Bart
hasn't used it or won't use it, it's irrelevant.

...

> >That doesn't stop people design designing varieties of weird systems
> >that are incompatible with anything else, or with languages that expect
> >certain requirements to be met. Like in your link.
>
> That "weird" system processed ATM and teller transactions for hundreds
> of financial institutions over six processor generations (starting in
> the 1950's) for over fifty years. The larger systems sold for $1.5 million
> USD in the 1980s'.

Still irrelevant in Bart-world. Only computers Bart has encountered and
understands can be discussed. This is useful for debate and is analogous
to the "No True Scotsman" principle.

David Brown

unread,
Sep 25, 2018, 4:47:18 AM9/25/18
to
On 25/09/18 00:07, Bart wrote:
> On 24/09/2018 21:51, David Brown wrote:
>> On 24/09/18 17:18, Bart wrote:
>
>>> Since then, I don't think any of the 9 or 10 architectures I've coded
>>> for (and a few more I've studied) would have had anything other than
>>> an all 1s representation of -1.)
>>
>> There have never been many systems that had something other than all
>> 1's for -1, but there have been a few. You are not likely to come
>> across them, especially in modern C programming. (I have worked with
>> programming language implementations where -1 had a representation
>> other than all 1's, but it was not C.)
>
> In software anyone can make up their own schemes. As a simple example,
> they can choose to use floating point representation for integers, where
> -1 might be stored as:
>
> -100000000010000000000000000000000000000000000000000000000000000
>

That is approximately the format used by the implementation I was
thinking about (I haven't counted the number of 0's to be sure). It had
a 32-bit number format that could store either an integer in 24 bits
plus a sign bit, or a floating point value with 24-bit mantissa.

> in binary. And I use a big int library that uses signed-magnitude
> decimals with 'digits' that go from 0 to 999999. -1 would be the two
> 32-bit words (1,1).
>
> This is about common machine representations and languages that work
> closely with such representations.

Well, the thread was never about this at all - the representation of -1
on the machine is irrelevant to the fact that "-1" converted to an
unsigned type in C always gives you the maximum value of that type.

>
>>> (With pen and paper, if doing it in decimal, you also make the
>>> interesting discovery that -1 can be represented as an infinite
>>> sequence of 9s, ie. "....999". Negative numbers with denoted with
>>> "-", really signed magnitude, aren't needed after all!)
>>
>> That is just nonsense.
>
> (It what way? If I add 1 to "...999" I get 0, just as I would adding 1
> to -1.

No, you don't. I can't imagine what jumble of ideas makes you think that.

An infinite sequence of 9's is infinity. Adding 1 leaves it unchanged
as infinity. Normal mathematical integers do not wrap - nor do they
have a maximum value. (If you are interested in infinite arithmetic, we
can go into more detail, but it would be very off-topic.)

>
> If I multiply "...999" by itself I get "...0001", or +1, just as I get
> if I square -1.
>
> If I multiply it by 5 I get "...995", which if I add +5, gives me 0,
> just as -5 would do.
>
> So it all seems to work.

It only /appears/ to work if you don't actually bother doing the
calculations - you just handle an arbitrarily small number of the least
significant digits. But the maths is not integer maths, you don't have
proper rules for handling them (just try division), and if you work
things through enough to get rigorous definitions of operations and a
mapping to normal integers, you'll find that your "...999" bit is just
an inconvenient way of writing "-".

>
> But having to have an infinite number of leading digits, or using a
> fixed number with the left-most one designated a sign digit, is
> inconvenient. Inside a computer however and using binary (and with a
> fixed number of digits, not infinite), it is very helpful.)
>

It is helpful, yes. But that is mainly an effect of the way we tend to
implement arithmetic using logic gates - nothing more than that. In a
finite computer you are always going to have a finite model for
arithmetic - you can't implement mathematical integers. Two's
complement with fixed sizes is a representation that gives a good
balance between efficient implementation and useful features - it does
not mean that two's complement is inherently more "natural" or "correct"
than other representations of negative numbers.

>>>
>>>> I don't want to discourage anyone from giving advice but when you have
>>>> explicitly stated that you don't want to learn what you think of as C's
>>>> crazy rules, it seems odd that you choose to.
>>>
>>> Well I read your reply to the OP, and I couldn't make head or tail of
>>> it, not even on a second reading. Sometimes you want to keep those
>>> crazy rules at bay as much as possible and just try and make
>>> practical common sense work.
>>>
>> Try again, and if it still doesn't make sense, ask someone about the
>> parts you have trouble with.
>
> Here's the fast part:
>
> "A signed integer value is converted to an unsigned type by subtracting
> (repeatedly if necessary) one more than the maximum value of that type."
>

(It should read "adding or subtracting", not just "subtracting".)

When you have a representation with no padding bits (as you usually do,
for all types other than _Bool), this has exactly the same mathematical
effect as you would get by taking the signed integer in two's complement
representation, sign-extending as much as necessary if the new unsigned
type has more bits. Then truncate from the LSB to the size of the
unsigned type.

> Assuming "that type" means the unsigned type we're trying to determine
> the maximum value of, then that method for working out that value,
> requires that you first know what that value is!

The /compiler/ needs to know the value - the programmer doesn't.
Clearly the compiler always knows the size of the types involved.

>
> If someone is trying to work through that with pen and paper, then they
> will need to know SIZE_MAX before they can determine SIZE_MAX.
>

The point of calculations like "(size_t) -1" is that they work for any C
implementation - with values that are dependent on the implementation.
If you want to do this by pen and paper, you need to know which C
implementation you are using - and then you can look up the sizes in the
documentation. It does not make sense to try to get a calculation on
paper that is independent of the compiler.

>> If you don't understand something, ask - don't try to add your own
>> alternative confusions as an answer to someone else's question.
>
> C doesn't have a monopoly on signed and unsigned representations of
> binary integers. These same problems come up with any number of
> languages, and outside languages too as they are among the fundamental
> characteristics of nearly all computers.
>

True.

> That the byte pattern 11111111, is 255 or the maximum value of an
> unsigned byte, if interpreted one way, or -1 if interpreted as signed -
> for twos complement - has been very well known for decades. And is the
> basis for using ((size_t)-1) since the -1 gives you as many ones as needed.
>
>

8 bits is a common size of byte - it is the standard for all but niche
situations. The same applies to two's complement for signed integer
representation. However, these are /not/ fundamental to computing -
they are merely convenient standards that works well in practice, and
have thus become dominant.

That means that for all but the most unusual implementations (which /do/
exist, even if you never see them yourself), it is correct to say that
((size_t) -1) will give you lots of 1's. But what is /always/ correct
in C - even for the weirdest implementations, is that ((size_t) - 1)
will give you the maximum value of type size_t.

And the OP was not interested in having a bunch of 1's. He was
interested in having the maximum value of type size_t.

Of course, there is no guarantee that size_t is the largest unsigned
type. In C99, that would be uintmax_t, which is guaranteed to be able
to represent any value of any unsigned type. (Note that pointers can be
bigger.) It is entirely possible for a C implementation on a 64-bit
computer to have size_t as 64-bit, but have solid support for 128-bit
arithmetic and define uintmax_t to 128-bit.

And for most C types, there are standard library macros for the maximum
values - such as UINTMAX_MAX. size_t is a bit unusual in this respect,
which is why something like ((size_t) -1) might be useful.

Bart

unread,
Sep 25, 2018, 5:08:25 AM9/25/18
to
And presumably irrelevant also in the world in which people program in
Java, C#, Go, Rust, D, Swift, and Scala, which all appear to use
power-of-two integer types with twos complement representation.

They're not like C (with its ugly sister C++) which oohs and aahs over
the question and never likes to commit itself over something so fundamental.

Never mind that 99.9% of C programs run on the same hardware as all
those other languages.

Notes:

(1) The poster of the link to that odd machine himself admitted it was a
poor fit for a C target, so it was too wacky even for C.

From which you could speculate that the C committee might also have
considered that architecture irrelevant. They appear to live in
Bart-world too.

(2) The OP's code fragment was in a module supporting a Fortran
implementation.


--
bart

Malcolm McLean

unread,
Sep 25, 2018, 5:51:29 AM9/25/18
to
On Tuesday, September 25, 2018 at 9:47:18 AM UTC+1, David Brown wrote:
> On 25/09/18 00:07, Bart wrote:
>
> >
> >>> (With pen and paper, if doing it in decimal, you also make the
> >>> interesting discovery that -1 can be represented as an infinite
> >>> sequence of 9s, ie. "....999". Negative numbers with denoted with
> >>> "-", really signed magnitude, aren't needed after all!)
> >>
> >> That is just nonsense.
> >
> > (It what way? If I add 1 to "...999" I get 0, just as I would adding 1
> > to -1.
>
> No, you don't. I can't imagine what jumble of ideas makes you think that.
>
> An infinite sequence of 9's is infinity. Adding 1 leaves it unchanged
> as infinity. Normal mathematical integers do not wrap - nor do they
> have a maximum value. (If you are interested in infinite arithmetic, we
> can go into more detail, but it would be very off-topic.)
>
You don't get what Bart is saying.
You can extend the principles of two's complement arithmetic to other
bases, then it works as Bart says.

Bart

unread,
Sep 25, 2018, 5:54:29 AM9/25/18
to
On 25/09/2018 09:47, David Brown wrote:
> On 25/09/18 00:07, Bart wrote:

>> (It what way? If I add 1 to "...999" I get 0, just as I would adding 1
>> to -1.
>
> No, you don't. I can't imagine what jumble of ideas makes you think that.
>
> An infinite sequence of 9's is infinity. Adding 1 leaves it unchanged
> as infinity. Normal mathematical integers do not wrap - nor do they
> have a maximum value.

Write down a twos complement representation of -1, which is 11111111 for
8 bits. Add 1 to it. You will find the first carry propagates all the
way to the left, giving you 00000000, or 0. The final carry has to be
discarded as we've run out of bits (perhaps tick an overflow box).

But we've taken what looks like the largest possible magnitude for that
number of bits, 11111111, and made it zero by adding 1.

Now repeat the exercise with 64 bits instead of 8. Then do it again with
64,000. If you take wider and wider numbers, is there any point at which
any number of 1s will not yield zero if you add 1 from the right-hand end?

If not, why shouldn't that be the case with an infinite number of ones?
And if it is the case, why shouldn't that work with an infinite number
of 9s?

>> "A signed integer value is converted to an unsigned type by subtracting
>> (repeatedly if necessary) one more than the maximum value of that type."
>>
>
> (It should read "adding or subtracting", not just "subtracting".)

If this is 16 bits and this means adding or subtracting 65536 from a
signed value, isn't that undefined because it will overflow or underflow?

Or is it necessary to first convert that signed value to unsigned, then
do the operation with two unsigned operands?

In that case that appears to be yet another impossibility: to convert
signed to unsigned, you have to apply a transformation that first
converts the signed value to unsigned!

(However, I admit that I was wrong about why (size_t)-1 works. It's
dependent on how the language converts signed to unsigned types.

If there is a widening involved, then it relies on sign-extending the
signed value to the final width first.

In my language, it's different: when converting a signed value to a
wider unsigned type, then it makes the assumption that the signed value
can be represented in the wider type (ie. is positive) and zero-extends it.

So an 8-bit -1 extended to 16-bits unsigned gives +255 (C gives you +65535).

On the other hand, getting the maximum value of any type is an intrinsic
feature.)

--
bart

Öö Tiib

unread,
Sep 25, 2018, 6:19:51 AM9/25/18
to
Problem is not that C (and C++) do leave more freedom of
implementation to define things. Freedom and flexibility is
complication for user but not evil in principle. It is actually
edge on market where other participants do not leave such freedom
and flexibility. Problem is elsewhere.

> Notes:
>
> (1) The poster of the link to that odd machine himself admitted it was a
> poor fit for a C target, so it was too wacky even for C.
>
> From which you could speculate that the C committee might also have
> considered that architecture irrelevant. They appear to live in
> Bart-world too.
>
> (2) The OP's code fragment was in a module supporting a Fortran
> implementation.

Problem is indeed in the fruits of that committee. They have done
only half of their work. Where that implementation must define
those things? In some sort of papers. Why? We can't #include papers.
Does the committee consist only of paper-gnawing rodents? Why there
are no standard way to check most of those implementation-defined
things compile-time?

There are no standard way to check in code what is going on starting
from most mundane things like what is the encoding that compiler
expects the very code to be in and then continuing to endianness,
alignment, how signedness is represented &c.

Therefore we can't static assert that the platform targeted is
indeed one of those 99.9%. We can't put the relevant static asserts
in front of example that we post. We can't cut all that further
controversy of EBCDICK 9-bit bytes of sign and magnitude with middle
endian in bitfield. Who does really benefit from that?

Ben Bacarisse

unread,
Sep 25, 2018, 6:43:11 AM9/25/18
to
David Brown <david...@hesbynett.no> writes:

> On 25/09/18 00:07, Bart wrote:
>> On 24/09/2018 21:51, David Brown wrote:
>>> On 24/09/18 17:18, Bart wrote:
<snip>
>>>> (With pen and paper, if doing it in decimal, you also make the
>>>> interesting discovery that -1 can be represented as an infinite
>>>> sequence of 9s, ie. "....999". Negative numbers with denoted with
>>>> "-", really signed magnitude, aren't needed after all!)
>>>
>>> That is just nonsense.
>>
>> (It what way? If I add 1 to "...999" I get 0, just as I would adding 1
>> to -1.
>
> No, you don't. I can't imagine what jumble of ideas makes you think
> that.
>
> An infinite sequence of 9's is infinity.

An infinite sequence of 9s has no universally accepted meaning as
decimal notation is limited to finite sequences (to the left of any
'dot' at least). It's entirely reasonable to consider ...999 to be a
representation of -1.

> Adding 1 leaves it unchanged
> as infinity. Normal mathematical integers do not wrap - nor do they
> have a maximum value. (If you are interested in infinite arithmetic, we
> can go into more detail, but it would be very off-topic.)
>
>>
>> If I multiply "...999" by itself I get "...0001", or +1, just as I get
>> if I square -1.
>>
>> If I multiply it by 5 I get "...995", which if I add +5, gives me 0,
>> just as -5 would do.
>>
>> So it all seems to work.
>
> It only /appears/ to work if you don't actually bother doing the
> calculations - you just handle an arbitrarily small number of the least
> significant digits.

I don't understand the difference you are drawing between appearing to
work and actually working. For example, -1 should behave as if has an
unbounded sequence of 9 digits (or 1 digits in binary) even if it's more
convenient to write it as -1.

> But the maths is not integer maths, you don't have
> proper rules for handling them (just try division), and if you work
> things through enough to get rigorous definitions of operations and a
> mapping to normal integers, you'll find that your "...999" bit is just
> an inconvenient way of writing "-".

You seems to be saying that division goes wrong, but you can work things
through so it doesn't go wrong (which is indeed the case).

As for the convenience, I suppose it depends on exactly what you mean.
It would be surprising and unusual (maybe that's the inconvenience you
mean) if a programming language did:

?> 4 - 10
?> ...94

but it does not seem to me to be inconvenient. And if you allow … in
place of ..., and you elide the unnecessary 9, it's even the same number
of characters.

<snip>
--
Ben.

David Brown

unread,
Sep 25, 2018, 6:44:09 AM9/25/18
to
That was not what he was saying. (It is conceivable that that is what
he /thought/ he was saying - I am not convinced I have understood what
he meant rather than merely what he wrote.)

Of course you can do modulo arithmetic in any base you want. But he was
specifically talking about an /infinite/ sequence of 9's. That is a
different matter entirely.

Malcolm McLean

unread,
Sep 25, 2018, 6:49:16 AM9/25/18
to
On Tuesday, September 25, 2018 at 11:19:51 AM UTC+1, Öö Tiib wrote:
>
> There are no standard way to check in code what is going on starting
> from most mundane things like what is the encoding that compiler
> expects the very code to be in and then continuing to endianness,
> alignment, how signedness is represented &c.
>
> Therefore we can't static assert that the platform targeted is
> indeed one of those 99.9%. We can't put the relevant static asserts
> in front of example that we post. We can't cut all that further
> controversy of EBCDICK 9-bit bytes of sign and magnitude with middle
> endian in bitfield. Who does really benefit from that?
>
The answer is portable code.
If you stick to the basic types (not unit8_t and family) then code should
run on pretty much any machine. As long as you write pure functions
(actually what this newsgroup calls "Malcolm functions" but we'll leave
that for now) and you use size_t to index arrays, then you don't need
to know what the actual bit patterns are.
f you are writing low-level IO code, you might need to know bit patterns
to set hardware bits. But such code is inherently non-portable, you don't
need to query the sizes and bit layout of types because you will know
them.

Ben Bacarisse

unread,
Sep 25, 2018, 6:50:15 AM9/25/18
to
It's a /little/ bit more than changing base. You also have to extend
the usual notion of complement as well so that it applies when there is
no limit on the number of base X digits.

--
Ben.

David Brown

unread,
Sep 25, 2018, 7:16:05 AM9/25/18
to
On 25/09/18 11:54, Bart wrote:
> On 25/09/2018 09:47, David Brown wrote:
>> On 25/09/18 00:07, Bart wrote:
>
>>> (It what way? If I add 1 to "...999" I get 0, just as I would adding 1
>>> to -1.
>>
>> No, you don't. I can't imagine what jumble of ideas makes you think
>> that.
>>
>> An infinite sequence of 9's is infinity. Adding 1 leaves it unchanged
>> as infinity. Normal mathematical integers do not wrap - nor do they
>> have a maximum value.
>
> Write down a twos complement representation of -1, which is 11111111 for
> 8 bits. Add 1 to it. You will find the first carry propagates all the
> way to the left, giving you 00000000, or 0. The final carry has to be
> discarded as we've run out of bits (perhaps tick an overflow box).
>
> But we've taken what looks like the largest possible magnitude for that
> number of bits, 11111111, and made it zero by adding 1.
>
> Now repeat the exercise with 64 bits instead of 8. Then do it again with
> 64,000. If you take wider and wider numbers, is there any point at which
> any number of 1s will not yield zero if you add 1 from the right-hand end?
>

That's all fine so far.

> If not, why shouldn't that be the case with an infinite number of ones?

Because infinity is not a number. The rules break down if you try to
pretend it is.

When you have a finite number of digits, you have an maximum value and
wrapping from there to 0 as you add more to it - that is modulo
arithmetic. When you have an infinite number of digits, there is no
maximum value, no modulo, no wrapping. It is a /completely/ different
type of arithmetic, with very different rules.

Infinities are not easily understood - if you have not studied
mathematics at a university level, I can appreciate that it is not
obvious why something can work for any size of finite number and fail
completely for an infinite number.

> And if it is the case, why shouldn't that work with an infinite number
> of 9s?
>

The case for an infinite number of 9's is no different from that of an
infinite number of 1's - it is not the move from 1 to 9 (or binary to
decimal) that is the issue. It is the move from finite to infinite that
has the problem.

>>> "A signed integer value is converted to an unsigned type by subtracting
>>> (repeatedly if necessary) one more than the maximum value of that type."
>>>
>>
>> (It should read "adding or subtracting", not just "subtracting".)
>
> If this is 16 bits and this means adding or subtracting 65536 from a
> signed value, isn't that undefined because it will overflow or underflow?
>

Yes it is adding or subtracting 65536, no it is not undefined. The
operation here is in terms of the /value/, which is a mathematical
integer and does not overflow. When we say that "signed integer
arithmetic overflow is undefined", what we mean is that the attempt to
store the mathematically correct value in a signed type that is too
small for it, us undefined behaviour. The problem does not happen when
adding 30,000 to 30,000 (using signed 16-bit ints, because the numbers
are easier) - the result of that addition is the /value/ 60,000. The
undefined behaviour is attempting to squeeze a value of 60,000 into a
box with a maximum of 32,767.

> Or is it necessary to first convert that signed value to unsigned, then
> do the operation with two unsigned operands?

No, you have to distinguish between the value of the expression, which
is allowed to be any mathematical integer, and the representable values
of the type, which are limited in range.

>
> In that case that appears to be yet another impossibility: to convert
> signed to unsigned, you have to apply a transformation that first
> converts the signed value to unsigned!

Do you understand the term "reductio ad absurdum" ? If you take a
premise and use it to derive something impossible, then your premise was
wrong. In this case, since you have reasoned your way to an
impossibility, it should have been clear to you that your idea that it
is "necessary first to convert that signed value to unsigned" must be
incorrect.

>
> (However, I admit that I was wrong about why (size_t)-1 works. It's
> dependent on how the language converts signed to unsigned types.
>

Yes, exactly.

> If there is a widening involved, then it relies on sign-extending the
> signed value to the final width first.
>

No, not at all. It works by value, not representation - the number of
bits in the original -1 is irrelevant.

> In my language, it's different: when converting a signed value to a
> wider unsigned type, then it makes the assumption that the signed value
> can be represented in the wider type (ie. is positive) and zero-extends it.
>
> So an 8-bit -1 extended to 16-bits unsigned gives +255 (C gives you
> +65535).

That would be surprising, IMHO. You pick the rules you want for your
own language, and people using the language should learn those rules.
The same applies to C.

>
> On the other hand, getting the maximum value of any type is an intrinsic
> feature.)
>

That would be a convenient feature.

(C has macros for the maximum value of most types in <limits.h> or
<stdint.h>, but not for size_t - and not in a way that you can write
something like "maxval(T)" for type T. C++ has
std::numeric_limits<T>::max().)



Bart

unread,
Sep 25, 2018, 7:57:06 AM9/25/18
to
On 25/09/2018 12:15, David Brown wrote:
> On 25/09/18 11:54, Bart wrote:

>> If this is 16 bits and this means adding or subtracting 65536 from a
>> signed value, isn't that undefined because it will overflow or underflow?
>>
>
> Yes it is adding or subtracting 65536, no it is not undefined. The
> operation here is in terms of the /value/, which is a mathematical
> integer and does not overflow. When we say that "signed integer
> arithmetic overflow is undefined", what we mean is that the attempt to
> store the mathematically correct value in a signed type that is too
> small for it, us undefined behaviour. The problem does not happen when
> adding 30,000 to 30,000 (using signed 16-bit ints, because the numbers
> are easier) - the result of that addition is the /value/ 60,000. The
> undefined behaviour is attempting to squeeze a value of 60,000 into a
> box with a maximum of 32,767.

Now you've got me confused. I thought a key example of C's undefined
behaviour is when signed arithmetic overflows. That would be the case
whether you stored the result somewhere or not.

So, if an implementation uses 16-bit ints, you have:

int a=32767, b=100;

And you do:

a+b;
f(a+b); // where f takes any numeric type
A[a+b];
unsigned c = a+b;

are saying that none of these is UB? Only:

int d = a+b;

?

>> Or is it necessary to first convert that signed value to unsigned, then
>> do the operation with two unsigned operands?
>
> No, you have to distinguish between the value of the expression, which
> is allowed to be any mathematical integer, and the representable values
> of the type, which are limited in range.

So an expression is evaluated independently of its type and UB never
occurs during the evaluation?

Then, like Schrodinger's cat, you don't know whether it was successful
or not until you copy the result into a variable? (Suppose you copied it
into a wider int type?)

I've leave it to others to comment further.

>> So an 8-bit -1 extended to 16-bits unsigned gives +255 (C gives you
>> +65535).
>
> That would be surprising, IMHO. You pick the rules you want for your
> own language, and people using the language should learn those rules.
> The same applies to C.

I can't see there's much advantage of one method over another. Copying a
negative value into an unsigned type is always going to have some problems.

In both cases, copying the u16 result back to i8 will give you back the -1.

In both cases, converting a i8 -1 to u16 then to i32 will give you
something other than -1.

> something like "maxval(T)" for type T. C++ has
> std::numeric_limits<T>::max().)

(I wonder if that still leads back to some macro in limits.h or stdint.h?)

--
bart

Öö Tiib

unread,
Sep 25, 2018, 8:45:14 AM9/25/18
to
Writing to and reading from portable file formats is not some sort
of "low level i/o". It is everyday necessity.
https://en.wikipedia.org/wiki/List_of_file_formats
It can no way be "inherently non-portable" but direct opposite to it
and need to query sizes and bit layouts of platform is apparent.
Otherwise how to correct the mismatches with what the sizes and
bit layouts are in a file what the program is reading/writing?

Lets drop binary and go text? It is being utterly devoid of reality
to stick only to letters of American-Latin alphabet and Arabian
numbers there. World where 92.2% of text content is UTF8
https://w3techs.com/technologies/details/en-utf8/all/all
it does not match with any expectations.

So how is program consisting of "Malcolm functions" useful for
anything if it is utterly incapable of communicating in actual
world that we live in?

David Brown

unread,
Sep 25, 2018, 9:14:16 AM9/25/18
to
On 25/09/18 13:56, Bart wrote:
> On 25/09/2018 12:15, David Brown wrote:
>> On 25/09/18 11:54, Bart wrote:
>
>>> If this is 16 bits and this means adding or subtracting 65536 from a
>>> signed value, isn't that undefined because it will overflow or
>>> underflow?
>>>
>>
>> Yes it is adding or subtracting 65536, no it is not undefined. The
>> operation here is in terms of the /value/, which is a mathematical
>> integer and does not overflow. When we say that "signed integer
>> arithmetic overflow is undefined", what we mean is that the attempt to
>> store the mathematically correct value in a signed type that is too
>> small for it, us undefined behaviour. The problem does not happen when
>> adding 30,000 to 30,000 (using signed 16-bit ints, because the numbers
>> are easier) - the result of that addition is the /value/ 60,000. The
>> undefined behaviour is attempting to squeeze a value of 60,000 into a
>> box with a maximum of 32,767.
>
> Now you've got me confused. I thought a key example of C's undefined
> behaviour is when signed arithmetic overflows. That would be the case
> whether you stored the result somewhere or not.
>

It doesn't matter if you "store" it somewhere or not (apologies for my
confusing wording - I am trying to express things in a way that I hope
will be clearer than the standards, since you have said you don't
understand them). When you write "a + b", the first thing is to
establish the types involved. "a" and/or "b" may need to be promoted
until they are both the same type and of rank (approximately meaning
"size", but not exactly) at least that of "int". "a" and "b" are then
converted to this common type, which will be the type of the expression.

Then the expression is figured out as though you had mathematical
integers to get the true result. If this result fits in the value range
of the expression's type, you are good to go. If not, you have an
"exceptional condition" and undefined behaviour.

> So, if an implementation uses 16-bit ints, you have:
>
> int a=32767, b=100;
>
> And you do:
>
> a+b;
> f(a+b); // where f takes any numeric type
> A[a+b];
> unsigned c = a+b;
>
> are saying that none of these is UB? Only:
>
> int d = a+b;
>
> ?

No, they are all undefined behaviour.

But the UB is caused by trying to fit 32867 into the range of "int" -
not by calculating 32767 + 100 -> 32867. (Of course, an implementation
does not need to do the calculation to generate 32867 - this is at a
theoretical level.)

>
>>> Or is it necessary to first convert that signed value to unsigned, then
>>> do the operation with two unsigned operands?
>>
>> No, you have to distinguish between the value of the expression, which
>> is allowed to be any mathematical integer, and the representable values
>> of the type, which are limited in range.
>
> So an expression is evaluated independently of its type and UB never
> occurs during the evaluation?
>
> Then, like Schrodinger's cat, you don't know whether it was successful
> or not until you copy the result into a variable? (Suppose you copied it
> into a wider int type?)
>

You are not copying it into a variable - you are fitting it into the
range of the expression's type. (If you assign the result of the
expression to a wider int type, that happens /after/ fitting it into the
smaller type. So if you write "long int x = a + b;" where "a" is 32767
and "b" is 100, and int is 16-bit, then it is still UB and it is
entirely reasonable for the compiler to set x to 32867, -32669, or
anything else it fancies.)

> I've leave it to others to comment further.
>
>>> So an 8-bit -1 extended to 16-bits unsigned gives +255 (C gives you
>>> +65535).
>>
>> That would be surprising, IMHO. You pick the rules you want for your
>> own language, and people using the language should learn those rules.
>> The same applies to C.
>
> I can't see there's much advantage of one method over another. Copying a
> negative value into an unsigned type is always going to have some problems.
>
> In both cases, copying the u16 result back to i8 will give you back the -1.
>
> In both cases, converting a i8 -1 to u16 then to i32 will give you
> something other than -1.
>
>> something like "maxval(T)" for type T. C++ has
>> std::numeric_limits<T>::max().)
>
> (I wonder if that still leads back to some macro in limits.h or stdint.h?)
>

It may do, or it may not - it is an implementation-dependent header.
Off-hand, I don't know the rules involved as to whether a C++ header
like <limits> is allowed to include the macros from <limits.h>. All I
can tell you here is that gcc does not - it has built-in macros such as
__INT_MAX__ (which are always allowed), and the values in both the C
<limits.h> macros and the C++ <limits> numeric_limits are given from
these built-in symbols.


Keith Thompson

unread,
Sep 25, 2018, 11:37:48 AM9/25/18
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:
[...]
> C defines 0u-1u to be -1, converted to unsigned. If you are going to
> avoid explaining the original issue, you need to explain this special
> subtraction that does give a mathematical negative number.

Strictly speaking, there's no type conversion in the expression
0u-1u. "A computation involving unsigned operands can never
overflow, because a result that cannot be represented by the
resulting unsigned integer type is reduced modulo the number that
is one greater than the largest value that can be represented by
the resulting type." That reduction is not a type conversion.

Bart

unread,
Sep 25, 2018, 12:43:56 PM9/25/18
to
On 25/09/2018 04:52, Ben Bacarisse wrote:
> Bart <b...@freeuk.com> writes:

>> So you have [an] unsigned 1 being subtracted from [an] unsigned 0.

> The result of that subtraction is a mathematical value: -1. This value
> is then converted to size_t because that's the type determined by the
> usual arithmetic conversions (provided Keith's caveat does not apply).
> This is how C defines (size_t)0-(size_t)1.
>
> I.e. the way C explains your expression requires the reader to already
> know what (size_t)-1 means.
>
> Now the reader may know something about how machines do arithmetic, and
> may know or guess what your are implying with this special "unsigned
> subtraction".

For this purpose (the query in the OP) that may be enough. And may be
preferred to analysing what the C standard says in too much detail.

Because then you are left with an actual operation that is done by the
hardware, and a virtual one in an imaginary machine that is done in
parallel, according to how I read your post. That raises all sorts of
new questions.

--
bart

Nick Bowler

unread,
Sep 25, 2018, 1:38:44 PM9/25/18
to
On Mon, 24 Sep 2018 14:25:24 +0100, Ben Bacarisse wrote:
> pedr...@lycos.com writes:
>> I thought size_t means an unsigned integer (at least 16 bits), so how
>> can you use it with -1?
>
> Copying from the subject:
>
> #define SIZE_MAX ((size_t)-1)
>
> A signed integer value is converted to an unsigned type by subtracting
> (repeatedly if necessary) one more than the maximum value of that type.
> This is "reduction modulo 2**w" where w is the number of value bits in
> the unsigned type. As a result, when T is an unsigned integer type,
> (T)-1 is the maximum value that T can represent.
[...]
> C99 and later define SIZE_MAX in a header called stdint.h.

For what it's worth, while C99 defines a macro called SIZE_MAX in
<stdint.h> it is very different from the above definition. That's
because ((size_t)-1) does not work as described above when used in
#if preprocessing directives.

David Brown

unread,
Sep 26, 2018, 3:15:05 AM9/26/18
to
That implies there is a specific way to define SIZE_MAX in <stdint.h>.
There is no fixed way - it is implementation-specific. But that is
exactly why it is in the standard headers here. It could be defined as
just a literal number, or using a compiler-specific built-in predefined
macro, or using conditional compilation to figure out the platform, or
any one of a dozen other ways.

If you are using C99, then #include <stdint.h> and use the standard
SIZE_MAX. If not, then ((size_t) -1) is as good and portable a way as any.

Malcolm McLean

unread,
Sep 26, 2018, 5:46:10 AM9/26/18
to
There's no need to make binary file format parsing non-portable.
Even floating point values can be read and written portably, though this
isn't entirely trivial.
>
> So how is program consisting of "Malcolm functions" useful for
> anything if it is utterly incapable of communicating in actual
> world that we live in?
>
"Malcolm functions" don't do IO. So a program cannot consist entirely
of "Malcolm functions". The idea is that you write the algorithmic core
in Malcolm functions, then separate that out so the core is portable.


Malcolm McLean

unread,
Sep 26, 2018, 6:00:52 AM9/26/18
to
On Tuesday, September 25, 2018 at 12:16:05 PM UTC+1, David Brown wrote:
>
> Infinities are not easily understood - if you have not studied
> mathematics at a university level, I can appreciate that it is not
> obvious why something can work for any size of finite number and fail
> completely for an infinite number.
>
If we want we can say that we have the sequence ...99999.0, and infinite series
of 9s extending leftwards. When we add one to it we get an infinite series
of rollovers so 1 ...00000.0 The one disappears off to infinity, so we get
0.
That's our system of symbols.

David Brown

unread,
Sep 26, 2018, 7:01:51 AM9/26/18
to
That's fine - /if/ you are willing to re-define what you mean by "add",
and perhaps also what you mean be "infinite" and your symbols. In
standard mathematics, the entity represented by "an infinite sequence of
9's" is the same thing as that represented by "1 followed by an infinite
sequence of 0's". Colloquially, if you add 1 to infinite you still have
infinity.

Of course it is possible to invent a representation like this, and
arithmetic operators on it. With enough effort, you'll have produced
something isomorphic to normal integer arithmetic but with "...999"
replacing the minus sign. It is an extraordinarily pointless exercise.

(There is real, useful mathematics which involve calculations on
infinity. When studying ordering, for example, you can make use of an
infinity called "omega" which is the smallest ordinal coming after all
finite ordinals. And (omega + 1) comes after omega - but (1 + omega) is
still just omega, based on the definitions of omega and addition usually
used.)

Wouter Verhelst

unread,
Sep 26, 2018, 7:03:14 AM9/26/18
to
On 9/26/18 12:00 PM, Malcolm McLean wrote:
> On Tuesday, September 25, 2018 at 12:16:05 PM UTC+1, David Brown wrote:
>>
>> Infinities are not easily understood - if you have not studied
>> mathematics at a university level, I can appreciate that it is not
>> obvious why something can work for any size of finite number and fail
>> completely for an infinite number.
>>
> If we want we can say that we have the sequence ...99999.0, and infinite series
> of 9s extending leftwards.

Here you speak of "an infinite series of [digit]", which is the
schoolbook definition of ∞, infinity.

> When we add one to it we get an infinite series
> of rollovers so 1 ...00000.0

No. You'd have ∞ + 1, which is still ∞.

Infinity is an absorbing element to addition (and multiplication too,
obviously). You can add more and more to infinity, you'll end up with
the very same infinity.

Bart

unread,
Sep 26, 2018, 7:46:19 AM9/26/18
to
On 26/09/2018 12:01, David Brown wrote:
> On 26/09/18 12:00, Malcolm McLean wrote:
>> On Tuesday, September 25, 2018 at 12:16:05 PM UTC+1, David Brown wrote:
>>>
>>> Infinities are not easily understood - if you have not studied
>>> mathematics at a university level, I can appreciate that it is not
>>> obvious why something can work for any size of finite number and fail
>>> completely for an infinite number.
>>>
>> If we want we can say that we have the sequence ...99999.0, and infinite series
>> of 9s extending leftwards. When we add one to it we get an infinite series
>> of rollovers so 1 ...00000.0 The one disappears off to infinity, so we get
>> 0.
>> That's our system of symbols.
>>
>
> That's fine - /if/ you are willing to re-define what you mean by "add",
> and perhaps also what you mean be "infinite" and your symbols. In
> standard mathematics, the entity represented by "an infinite sequence of
> 9's" is the same thing as that represented by "1 followed by an infinite
> sequence of 0's". Colloquially, if you add 1 to infinite you still have
> infinity.
>
> Of course it is possible to invent a representation like this, and
> arithmetic operators on it. With enough effort, you'll have produced
> something isomorphic to normal integer arithmetic but with "...999"
> replacing the minus sign. It is an extraordinarily pointless exercise.

Yes, completely pointless. Apart from realising, while playing with it,
you don't need an infinite number of digits, but can stop at N, and can
use binary instead of decimal, and that you've just discovered twos
complement.

Which can be used to add any mix of positive and negative numbers with
exactly the same circuit; you don't need special handling for the sign.

The usefulness can simply be in learning that ...999 /could/ represent
negative values, despite they appearing to be intuitively massive
positive quantities.

Now, when you rewind that tape so that the counter goes from 0123 to
9998, you don't have to pretend that 9998 represents minus 2, it could
actually /be/ -2!

--
bart

Malcolm McLean

unread,
Sep 26, 2018, 7:47:06 AM9/26/18
to
Yes, but you've replaced ...999999.0 by the flattened 8 sign that I can't type.
That's also legitimate, but you're using a different notation for infinity,
so you get a different result. Bart uses infinite leftwards extension, not
a special symbol for infinity.

Malcolm McLean

unread,
Sep 26, 2018, 7:57:58 AM9/26/18
to
Exactly. We can build a denary computer that uses 9999999999 as -1,
maybe we can even make it so that numbers have arbitrary lengths of
digits, limited only by memory. It's a useful exercise, if you weren't
previously sure how to extend two's complement, and assuming that you've
some requirement for denary numbers. But you need a bit of flexibility
of thought.

Wouter Verhelst

unread,
Sep 26, 2018, 8:47:51 AM9/26/18
to
On 9/26/18 1:46 PM, Malcolm McLean wrote:
> On Wednesday, September 26, 2018 at 12:03:14 PM UTC+1, Wouter Verhelst wrote:
>> On 9/26/18 12:00 PM, Malcolm McLean wrote:
>>> On Tuesday, September 25, 2018 at 12:16:05 PM UTC+1, David Brown wrote:
>>>>
>>>> Infinities are not easily understood - if you have not studied
>>>> mathematics at a university level, I can appreciate that it is not
>>>> obvious why something can work for any size of finite number and fail
>>>> completely for an infinite number.
>>>>
>>> If we want we can say that we have the sequence ...99999.0, and infinite series
>>> of 9s extending leftwards.
>>
>> Here you speak of "an infinite series of [digit]", which is the
>> schoolbook definition of ∞, infinity.
>>
>>> When we add one to it we get an infinite series
>>> of rollovers so 1 ...00000.0
>>
>> No. You'd have ∞ + 1, which is still ∞.
>>
>> Infinity is an absorbing element to addition (and multiplication too,
>> obviously). You can add more and more to infinity, you'll end up with
>> the very same infinity.
>
> Yes, but you've replaced ...999999.0 by the flattened 8 sign that I can't type.

compose-8-8

(you may not have compose on your keyboard. Sorry, can't help you then...)

> That's also legitimate, but you're using a different notation for infinity,
> so you get a different result.

Well, no. The mathematical theory behind ∞ is distinct from the
notation. Claiming otherwise is like saying "you used * rather than . to
signal multiplication, so it's normal that the result is different!" --
it makes no sense.

> Bart uses infinite leftwards extension, not
> a special symbol for infinity.

infinity is infinity, no matter how you write it.

David Brown

unread,
Sep 26, 2018, 10:03:11 AM9/26/18
to
That is an extremely round-about way to figure out two's complement. I
think the obvious way is to think of modulo arithmetic - there is no
need to go via completely incorrect leaps of logic involving infinities,
where your series of mistakes happens to land you on something that
works in a different way that happens to be useful.

And of course, two's complement arithmetic does not follow the rules of
mathematical integer arithmetic.

> Which can be used to add any mix of positive and negative numbers with
> exactly the same circuit; you don't need special handling for the sign.
>

Yes, you do need handling for the sign - for division, for right-shift,
and for more complex operations such as saturation. Two's complement is
a very convenient representation that gives you efficient implementation
of many common operations on numbers - there is no doubt about that.
But it is /not/ any kind of magical choice of representation, it does
not make everything simple, it does not give you the correct answers
when you put in invalid data, it does not give you a sensible overflow
behaviour, and it is not the best choice for all uses.

But overall, it is usually the most efficient compromise for a
representation of signed integers for use in computers.

> The usefulness can simply be in learning that ...999 /could/ represent
> negative values, despite they appearing to be intuitively massive
> positive quantities.
>

No, that is a daft way to learn it - partly because it is vastly
over-complicated, and partly because it is completely wrong.

You will get on far better by taking a clock, putting a "0" sticker over
the "12", and looking at adding and subtracting hours on that.

Once you get beyond the those, try the odometer on your car or bike.

These are counters that are naturally modulo, without trying to talk
about infinite numbers of digits that you sometimes pretend are there,
and sometimes pretend don't matter.

David Brown

unread,
Sep 26, 2018, 10:23:26 AM9/26/18
to
On 26/09/18 14:04, Wouter Verhelst wrote:
> On 9/26/18 1:46 PM, Malcolm McLean wrote:
>> On Wednesday, September 26, 2018 at 12:03:14 PM UTC+1, Wouter Verhelst wrote:
>>> On 9/26/18 12:00 PM, Malcolm McLean wrote:
>>>> On Tuesday, September 25, 2018 at 12:16:05 PM UTC+1, David Brown wrote:
>>>>>
>>>>> Infinities are not easily understood - if you have not studied
>>>>> mathematics at a university level, I can appreciate that it is not
>>>>> obvious why something can work for any size of finite number and fail
>>>>> completely for an infinite number.
>>>>>
>>>> If we want we can say that we have the sequence ...99999.0, and infinite series
>>>> of 9s extending leftwards.
>>>
>>> Here you speak of "an infinite series of [digit]", which is the
>>> schoolbook definition of ∞, infinity.
>>>
>>>> When we add one to it we get an infinite series
>>>> of rollovers so 1 ...00000.0
>>>
>>> No. You'd have ∞ + 1, which is still ∞.
>>>
>>> Infinity is an absorbing element to addition (and multiplication too,
>>> obviously). You can add more and more to infinity, you'll end up with
>>> the very same infinity.
>>
>> Yes, but you've replaced ...999999.0 by the flattened 8 sign that I can't type.
>
> compose-8-8
>

I don't have that one on my list. Maybe my distro is a bit old, or
perhaps it has a more limited compose set for my locale. But now that
you've written it, copy-and-paste works well: ∞

> (you may not have compose on your keyboard. Sorry, can't help you then...)
>
>> That's also legitimate, but you're using a different notation for infinity,
>> so you get a different result.
>
> Well, no. The mathematical theory behind ∞ is distinct from the
> notation. Claiming otherwise is like saying "you used * rather than . to
> signal multiplication, so it's normal that the result is different!" --
> it makes no sense.

Agreed.

>
>> Bart uses infinite leftwards extension, not
>> a special symbol for infinity.
>
> infinity is infinity, no matter how you write it.
>

Well, not quite - the number of real numbers is a bigger infinity than
the number of integers, for example. But in this case, there is no need
to make a distinction.


Spiros Bousbouras

unread,
Sep 26, 2018, 10:44:19 AM9/26/18
to
On Wed, 26 Sep 2018 16:23:17 +0200
David Brown <david...@hesbynett.no> wrote:
> On 26/09/18 14:04, Wouter Verhelst wrote:

[...]

> > compose-8-8
> >
>
> I don't have that one on my list. Maybe my distro is a bit old, or
> perhaps it has a more limited compose set for my locale. But now that
> you've written it, copy-and-paste works well: ∞

In vim in insert mode you type
Ctrl-V u221E
(spaces in the previous line exist for readability and should be omitted).
To learn more one should do
:help i_ctrl-v

Options encoding and fileencoding should have values utf-8 so if
one doesn't have this as a default , they should first do
:let &l:encoding = "utf-8"
:let &l:fileencoding = "utf-8"

And yes , this is all off-topic but so is the discussion about infinity and
at least what I posted here is useful.

> > infinity is infinity, no matter how you write it.
> >
>
> Well, not quite - the number of real numbers is a bigger infinity than
> the number of integers, for example. But in this case, there is no need
> to make a distinction.

Or indeed have this discussion which would be pointless even for a mathematics
newsgroup.

--
Did you have a brain tumour for breakfast ?
"Heathers"

Malcolm McLean

unread,
Sep 26, 2018, 10:49:25 AM9/26/18
to
On Wednesday, September 26, 2018 at 3:03:11 PM UTC+1, David Brown wrote:
>
> You will get on far better by taking a clock, putting a "0" sticker over
> the "12", and looking at adding and subtracting hours on that.
>
Many a true word spoken in jest.
The clock was invented before Europeans really understood zero. When
zero was introduced, from India, it released a great deal of mathematics.
Had someone invented a symbol for zero for a clock face, it would have
changed the course of history.

Malcolm McLean

unread,
Sep 26, 2018, 10:52:14 AM9/26/18
to
> infinity is infinity, no matter how you write it.
>
No, mathematics is notation. If we use ... to represent an infinite series
rather than 8 on its side to represent infinity, we get a rather different
mathematics. Maybe less powerful, but still valid.

David Brown

unread,
Sep 26, 2018, 10:54:08 AM9/26/18
to
On 26/09/18 16:49, Malcolm McLean wrote:
> On Wednesday, September 26, 2018 at 3:03:11 PM UTC+1, David Brown wrote:
>>
>> You will get on far better by taking a clock, putting a "0" sticker over
>> the "12", and looking at adding and subtracting hours on that.
>>
> Many a true word spoken in jest.

What jest? Clocks are a good way to learn about modulo arithmetic, and
modulo arithmetic is what you need for understanding two's complement.

> The clock was invented before Europeans really understood zero. When
> zero was introduced, from India, it released a great deal of mathematics.
> Had someone invented a symbol for zero for a clock face, it would have
> changed the course of history.
>

That would probably have been the case regardless of how the zero was
introduced - the clock face would have nothing to do with it.

David Brown

unread,
Sep 26, 2018, 11:30:14 AM9/26/18
to
On 26/09/18 16:52, Malcolm McLean wrote:
> On Wednesday, September 26, 2018 at 1:47:51 PM UTC+1, Wouter Verhelst wrote:
>> On 9/26/18 1:46 PM, Malcolm McLean wrote:
>>
>>> That's also legitimate, but you're using a different notation for infinity,
>>> so you get a different result.
>>
>> Well, no. The mathematical theory behind ∞ is distinct from the
>> notation. Claiming otherwise is like saying "you used * rather than . to
>> signal multiplication, so it's normal that the result is different!" --
>> it makes no sense.
>>
>> infinity is infinity, no matter how you write it.
>>
> No, mathematics is notation.

No it is not.

The notation is like words. You need to use words to communicate, but a
cat is still a cat even if you call it "katt", "chat", "feline", or
whatever.

> If we use ... to represent an infinite series
> rather than 8 on its side to represent infinity, we get a rather different
> mathematics. Maybe less powerful, but still valid.
>

If you are using "..." to represent something other than infinity, then
it is not the same as infinity. Writing "...999" to mean "an infinite
sequence of 9's" gives you infinity. Writing ∞ is another very common
way of representing "infinity".

Of course ellipsis can mean something other than "infinity" - it usually
means that a pattern continues (either for a finite count, or
unendingly). But in this context, it meant infinity. Perhaps you
didn't think that's what it meant, but if you want to use some
notational definitions that don't match the common practice used by
others, you'll have to give the definitions too.

Malcolm McLean

unread,
Sep 26, 2018, 11:50:27 AM9/26/18
to
In a sense it means "infinity". But actually it means something more like
"one less than infinity". Which is the same as "infinity" in your system
of notation, but not in Bart's. ...999998 is also "infinity", but it isn't
the same as ...999999, in Bart's system. When we increment ...999998, we
still get infinity. When we increment ...99999999 we don't, we get leading
zeros continuing forever. Which Bart doesn't distinguish from zero,
allowing him to define arithmetic with useful properties using his rules.




Bart

unread,
Sep 26, 2018, 1:10:08 PM9/26/18
to
On 26/09/2018 16:30, David Brown wrote:
> On 26/09/18 16:52, Malcolm McLean wrote:

>> If we use ... to represent an infinite series
>> rather than 8 on its side to represent infinity, we get a rather different
>> mathematics. Maybe less powerful, but still valid.
>>
>
> If you are using "..." to represent something other than infinity, then
> it is not the same as infinity. Writing "...999" to mean "an infinite
> sequence of 9's" gives you infinity. Writing ∞ is another very common
> way of representing "infinity".
>
> Of course ellipsis can mean something other than "infinity" - it usually
> means that a pattern continues (either for a finite count, or
> unendingly). But in this context, it meant infinity.

In my posts I meant an endless sequence of 9s, /written right to left/.
An infinite number of them, if you like. But not the value ∞.

The value I had in mind was one less than zero.

--
bart

Nick Bowler

unread,
Sep 26, 2018, 3:51:20 PM9/26/18
to
On Wed, 26 Sep 2018 09:14:56 +0200, David Brown wrote:
> On 25/09/18 19:38, Nick Bowler wrote:
>> On Mon, 24 Sep 2018 14:25:24 +0100, Ben Bacarisse wrote:
>>> pedr...@lycos.com writes:
>>>> I thought size_t means an unsigned integer (at least 16 bits), so how
>>>> can you use it with -1?
>>>
>>> Copying from the subject:
>>>
>>> #define SIZE_MAX ((size_t)-1)
>>>
>>> A signed integer value is converted to an unsigned type by subtracting
>>> (repeatedly if necessary) one more than the maximum value of that type.
>>> This is "reduction modulo 2**w" where w is the number of value bits in
>>> the unsigned type. As a result, when T is an unsigned integer type,
>>> (T)-1 is the maximum value that T can represent.
>> [...]
>>> C99 and later define SIZE_MAX in a header called stdint.h.
>>
>> For what it's worth, while C99 defines a macro called SIZE_MAX in
>> <stdint.h> it is very different from the above definition. That's
>> because ((size_t)-1) does not work as described above when used in
>> #if preprocessing directives.
>>
>
> That implies there is a specific way to define SIZE_MAX in <stdint.h>.

No, I only imply that the above definition is NOT a valid implementation
of the SIZE_MAX macro from <stdint.h> as described in C99 and later.

> There is no fixed way - it is implementation-specific.

Right, but regardless of what a conforming implementation does in
<stdint.h>, the expansion of SIZE_MAX from that header will not look
like the sequence of tokens described above.

> If you are using C99, then #include <stdint.h> and use the standard
> SIZE_MAX. If not, then ((size_t) -1) is as good and portable a way as
> any.

Well, if a program actually depends on the C99 macro working like C99
says it does, ((size_t)-1) is neither a good nor portable replacement.

Spiros Bousbouras

unread,
Sep 26, 2018, 4:02:39 PM9/26/18
to
On Tue, 25 Sep 2018 03:19:39 -0700 (PDT)
Tiib wrote:
> Why there
> are no standard way to check most of those implementation-defined
> things compile-time?
>
> There are no standard way to check in code what is going on starting
> from most mundane things like what is the encoding that compiler
> expects the very code to be in and then continuing to endianness,
> alignment, how signedness is represented &c.

Why do you want to check these things during compilation ? Anyway ,
for representation of integers you can do the following

#define twos_complement ( (-1 & 3) == 3 )
#define ones_complement ( (-1 & 3) == 2 )
#define sign_and_magnitude ( (-1 & 3) == 1 )

For endianness what macros would you like ? I mean is there an exhaustive
list of all kinds of endianess available ?

Öö Tiib

unread,
Sep 26, 2018, 4:08:06 PM9/26/18
to
I wasn't writing that we can not construct portable algorithms.
Sure we can figure fair number of the properties of platform out with
a row of run-time experiments and then use these to construct portable
(but likely inefficient) bit crunching code.

I was writing that it is pointless waste of effort since these
fundamental properties are very well known to implementation and
so a requirement to expose these in compile-time accessible
manner (for maximal efficiency) is missing from standard.

> > So how is program consisting of "Malcolm functions" useful for
> > anything if it is utterly incapable of communicating in actual
> > world that we live in?
> >
> "Malcolm functions" don't do IO. So a program cannot consist entirely
> of "Malcolm functions". The idea is that you write the algorithmic core
> in Malcolm functions, then separate that out so the core is portable.

External communication is large part of any program. Usually it is more
than half of code base. Usage of modular architecture is always good
idea but only two modules ("core" and "exterior") might be slightly
too simplistic.

David Brown

unread,
Sep 26, 2018, 4:48:16 PM9/26/18
to
Which is the same as infinity. It is not a matter of notation, it is a
matter of the concept of infinity.

> Which is the same as "infinity" in your system
> of notation, but not in Bart's. ...999998 is also "infinity", but it isn't
> the same as ...999999, in Bart's system. When we increment ...999998, we
> still get infinity. When we increment ...99999999 we don't, we get leading
> zeros continuing forever. Which Bart doesn't distinguish from zero,
> allowing him to define arithmetic with useful properties using his rules.
>

If you have an entity from which you can subtract one and get a
different entity, then you do not have an infinity. The notation is
wrong, the concept is wrong, and it is not what anyone else would mean
by "infinity".

It is entirely possible to define all sorts of mathematical structures.
You could work with a set of objects of type "a * w + b", where "a" and
"b" are integers, "w" is not an integer but is a special entity, and
where you work with equivalence classes for each "b" containing "a * w +
b" for all values of "a". I am not sure whether you could get a
consistent set of arithmetic operations on this structure (i.e., whether
or not it is a field) or if you would need something more - that would
require some thought. But while your "w" would have some aspects in
common with a conventional infinity, it would not be that simple.

And while it might be a fun mathematical distraction, it would not be
helpful for understanding two's complement arithmetic, which is a far
simpler concept.



David Brown

unread,
Sep 26, 2018, 4:50:23 PM9/26/18
to
And endless sequence of 9's, regardless of which direction they are
written (the distinction makes no sense) is infinite. That is what is
meant by the term "infinity" (unless you are dealing with more advanced
transfinite mathematics).

> The value I had in mind was one less than zero.
>

I realise that was in your mind. It bore no relation to what you wrote.

David Brown

unread,
Sep 26, 2018, 4:53:46 PM9/26/18
to
On 26/09/18 21:51, Nick Bowler wrote:
> On Wed, 26 Sep 2018 09:14:56 +0200, David Brown wrote:
>> On 25/09/18 19:38, Nick Bowler wrote:
>>> On Mon, 24 Sep 2018 14:25:24 +0100, Ben Bacarisse wrote:
>>>> pedr...@lycos.com writes:
>>>>> I thought size_t means an unsigned integer (at least 16 bits), so how
>>>>> can you use it with -1?
>>>>
>>>> Copying from the subject:
>>>>
>>>> #define SIZE_MAX ((size_t)-1)
>>>>
>>>> A signed integer value is converted to an unsigned type by subtracting
>>>> (repeatedly if necessary) one more than the maximum value of that type.
>>>> This is "reduction modulo 2**w" where w is the number of value bits in
>>>> the unsigned type. As a result, when T is an unsigned integer type,
>>>> (T)-1 is the maximum value that T can represent.
>>> [...]
>>>> C99 and later define SIZE_MAX in a header called stdint.h.
>>>
>>> For what it's worth, while C99 defines a macro called SIZE_MAX in
>>> <stdint.h> it is very different from the above definition. That's
>>> because ((size_t)-1) does not work as described above when used in
>>> #if preprocessing directives.
>>>
>>
>> That implies there is a specific way to define SIZE_MAX in <stdint.h>.
>
> No, I only imply that the above definition is NOT a valid implementation
> of the SIZE_MAX macro from <stdint.h> as described in C99 and later.

The wording you used, IMHO, implied that. But I did not think you
intended to imply it, which is why I made the distinction.

>
>> There is no fixed way - it is implementation-specific.
>
> Right, but regardless of what a conforming implementation does in
> <stdint.h>, the expansion of SIZE_MAX from that header will not look
> like the sequence of tokens described above.

Agreed entirely.

>
>> If you are using C99, then #include <stdint.h> and use the standard
>> SIZE_MAX. If not, then ((size_t) -1) is as good and portable a way as
>> any.
>
> Well, if a program actually depends on the C99 macro working like C99
> says it does, ((size_t)-1) is neither a good nor portable replacement.
>

It is entirely fine in the context in which it is used by the OP. I
agree that it cannot be used in all the same contexts as the C99
standard SIZE_MAX - which is why C99 provides this macro instead of
letting people just use ((size_t) -1) :-)

Öö Tiib

unread,
Sep 26, 2018, 4:54:26 PM9/26/18
to
On Wednesday, 26 September 2018 23:02:39 UTC+3, Spiros Bousbouras wrote:
> On Tue, 25 Sep 2018 03:19:39 -0700 (PDT)
> Tiib wrote:
> > Why there
> > are no standard way to check most of those implementation-defined
> > things compile-time?
> >
> > There are no standard way to check in code what is going on starting
> > from most mundane things like what is the encoding that compiler
> > expects the very code to be in and then continuing to endianness,
> > alignment, how signedness is represented &c.
>
> Why do you want to check these things during compilation?

Because obviously all processing that is done during compilation has
zero run time cost. And most common issue I listed there:

Spiros Bousbouras

unread,
Sep 26, 2018, 5:15:23 PM9/26/18
to
On Wed, 26 Sep 2018 13:54:12 -0700 (PDT) Tiib wrote:
> On Wednesday, 26 September 2018 23:02:39 UTC+3, Spiros Bousbouras wrote:
> > On Tue, 25 Sep 2018 03:19:39 -0700 (PDT)
> > Tiib wrote:
> > > Why there
> > > are no standard way to check most of those implementation-defined
> > > things compile-time?
> > >
> > > There are no standard way to check in code what is going on starting
> > > from most mundane things like what is the encoding that compiler
> > > expects the very code to be in and then continuing to endianness,
> > > alignment, how signedness is represented &c.
> >
> > Why do you want to check these things during compilation?
>
> Because obviously all processing that is done during compilation has
> zero run time cost.

For the things you mentioned the checking can be done at programme start up
and will increase the start up time by less than 1 microsecond. So I don't
see it as a problem.

> And most common issue I listed there:
>
> > > Therefore we can't static assert that the platform targeted is
> > > indeed one of those 99.9%. We can't put the relevant static asserts
> > > in front of example that we post.

I'm not sure what this sentence means. Do you mean post here ? Has it ever
happened that you wanted to put some static asserts in code that you posted
here and couldn't because the C standard doesn't provide a way ? And why
couldn't you put runtime checks ? Why couldn't you explain in words the
additional assumptions beyond the C standard that your code needed ? Without
some example(s) I don't really know what you mean.

> > > We can't cut all that further
> > > controversy of EBCDICK 9-bit bytes of sign and magnitude with middle
> > > endian in bitfield.

I don't know what this means.

Bart

unread,
Sep 26, 2018, 5:30:48 PM9/26/18
to
On 26/09/2018 21:50, David Brown wrote:
> On 26/09/18 19:09, Bart wrote:
>> On 26/09/2018 16:30, David Brown wrote:
>>> On 26/09/18 16:52, Malcolm McLean wrote:
>>
>>>> If we use ... to represent an infinite series
>>>> rather than 8 on its side to represent infinity, we get a rather
>>>> different
>>>> mathematics. Maybe less powerful, but still valid.
>>>>
>>>
>>> If you are using "..." to represent something other than infinity, then
>>> it is not the same as infinity.  Writing "...999" to mean "an infinite
>>> sequence of 9's" gives you infinity.  Writing ∞ is another very common
>>> way of representing "infinity".
>>>
>>> Of course ellipsis can mean something other than "infinity" - it usually
>>> means that a pattern continues (either for a finite count, or
>>> unendingly).  But in this context, it meant infinity.
>>
>> In my posts I meant an endless sequence of 9s, /written right to
>> left/. An infinite number of them, if you like. But not the value ∞.
>>
>
> And endless sequence of 9's, regardless of which direction they are
> written (the distinction makes no sense) is infinite.

'infinite' or 'infinity'?

If you mean the latter, then no it doesn't. I have an infinite number of
symbols (the digits 0 thru 9), to which I can ascribe any meaning I like.

And the direction is crucial, since we need to start at the least
significant end.

Actually, we don't need an infinite number of digits to show the
patterns, a finite number will do, except that I know have to say the
numbers wrap.

So your objections no longer matter.

  That is what is
> meant by the term "infinity" (unless you are dealing with more advanced
> transfinite mathematics).
>
>> The value I had in mind was one less than zero.
>>
>
> I realise that was in your mind.  It bore no relation to what you wrote.

You're not going to let this go are you?


--
bart

james...@alumni.caltech.edu

unread,
Sep 26, 2018, 6:33:20 PM9/26/18
to
On Wednesday, September 26, 2018 at 5:15:23 PM UTC-4, Spiros Bousbouras wrote:
> On Wed, 26 Sep 2018 13:54:12 -0700 (PDT) Tiib wrote:
> > On Wednesday, 26 September 2018 23:02:39 UTC+3, Spiros Bousbouras wrote:
> > > On Tue, 25 Sep 2018 03:19:39 -0700 (PDT)
> > > Tiib wrote:
...
> > > > Therefore we can't static assert that the platform targeted is
> > > > indeed one of those 99.9%. We can't put the relevant static asserts
> > > > in front of example that we post.
>
> I'm not sure what this sentence means. Do you mean post here ? Has it ever
> happened that you wanted to put some static asserts in code that you posted
> here and couldn't because the C standard doesn't provide a way ?

The first argument for a _Static_assert() is required to be an integer
constant expression (6.7.10p3), and therefore subject to the
restrictions given in 6.6p6. Could you identify an integer constant
expression that would serve to determine, for instance, whether a given
integer type is big-endian or little-endian? I know how to check that at
run-time. It's even simpler to do so if you're willing to pretend that
those are the only two possibilities, but I have no idea how to use an
integer constant expression for that purpose.

> couldn't you put runtime checks ?

Sure, but many people, myself included, strongly prefer compile-time
checking. If there were any good reason for not providing the needed
information in a way that could be used in a _Static_assert() or #error
directive, I would understand. But I know of no such reason.

> > > > We can't cut all that further
> > > > controversy of EBCDICK 9-bit bytes of sign and magnitude with middle
> > > > endian in bitfield.
>
> I don't know what this means.

I think he's giving examples of things that he thinks are hard to check
for at compile time. However, EBCDIC, 9-bit bytes, and use of sign-and-
magnitude representation by a signed integer type are all easy to check
for with _Static_assert(), particularly if you're only concerned with
distinguishing EBCDIC variants from ASCII variants, and don't worry
about any other encoding possibilities. Middle-endian is the only one
that's a problem - but it is in fact a problem.

Öö Tiib

unread,
Sep 26, 2018, 7:35:03 PM9/26/18
to
On Thursday, 27 September 2018 00:15:23 UTC+3, Spiros Bousbouras wrote:
> On Wed, 26 Sep 2018 13:54:12 -0700 (PDT) Tiib wrote:
> > On Wednesday, 26 September 2018 23:02:39 UTC+3, Spiros Bousbouras wrote:
> > > On Tue, 25 Sep 2018 03:19:39 -0700 (PDT)
> > > Tiib wrote:
> > > > Why there
> > > > are no standard way to check most of those implementation-defined
> > > > things compile-time?
> > > >
> > > > There are no standard way to check in code what is going on starting
> > > > from most mundane things like what is the encoding that compiler
> > > > expects the very code to be in and then continuing to endianness,
> > > > alignment, how signedness is represented &c.
> > >
> > > Why do you want to check these things during compilation?
> >
> > Because obviously all processing that is done during compilation has
> > zero run time cost.
>
> For the things you mentioned the checking can be done at programme start up
> and will increase the start up time by less than 1 microsecond. So I don't
> see it as a problem.

With 1 microsecond we can get that or other platform property but it is
too late to adapt the behavior of program run-time. That property tells
us how the platform behaves and so what corrective actions we need to
do with all data and operations that are altered. For example for to
conform with some binary i/o format or to correct bitwise arithmetic
or something about floating point or bitfields. There can be lot of that
in particular program and when we have run-time branching around each
then it is not 1 microsecond anymore. So in actual portable code bases
we see preprocessor metaprogramming using non-standard extension macros
instead of those "1 microsecond" run-time checks.

I meant *every* implementation-defined behavior in standard just
listed few from what it all starts and ended with &c.
https://en.wikipedia.org/wiki/Et_cetera

David Brown

unread,
Sep 27, 2018, 3:53:13 AM9/27/18
to
On 27/09/18 00:33, james...@alumni.caltech.edu wrote:
> On Wednesday, September 26, 2018 at 5:15:23 PM UTC-4, Spiros Bousbouras wrote:
>> On Wed, 26 Sep 2018 13:54:12 -0700 (PDT) Tiib wrote:
>>> On Wednesday, 26 September 2018 23:02:39 UTC+3, Spiros Bousbouras wrote:
>>>> On Tue, 25 Sep 2018 03:19:39 -0700 (PDT)
>>>> Tiib wrote:
> ...
>>>>> Therefore we can't static assert that the platform targeted is
>>>>> indeed one of those 99.9%. We can't put the relevant static asserts
>>>>> in front of example that we post.
>>
>> I'm not sure what this sentence means. Do you mean post here ? Has it ever
>> happened that you wanted to put some static asserts in code that you posted
>> here and couldn't because the C standard doesn't provide a way ?
>
> The first argument for a _Static_assert() is required to be an integer
> constant expression (6.7.10p3), and therefore subject to the
> restrictions given in 6.6p6. Could you identify an integer constant
> expression that would serve to determine, for instance, whether a given
> integer type is big-endian or little-endian? I know how to check that at
> run-time. It's even simpler to do so if you're willing to pretend that
> those are the only two possibilities, but I have no idea how to use an
> integer constant expression for that purpose.

If there were a way to check this at compile-time (for conditional
compilation, _Static_assert(), etc.) using only standard C or C++ then
there would be little reason for C++ to have introduced std::endian in
C++20.

Most compilers have pre-defined macros for endian determination, or the
compiler is tied to a single target with fixed endianness. So there are
headers available on the net that give you compile-time endian detection
that works on a great proportion of compilers, simply by determining the
compiler and using their specific symbols. It is not fully portable,
but it may work well enough in practice.

David Brown

unread,
Sep 27, 2018, 4:02:15 AM9/27/18
to
On 26/09/18 23:15, Spiros Bousbouras wrote:
> On Wed, 26 Sep 2018 13:54:12 -0700 (PDT) Tiib wrote:
>> On Wednesday, 26 September 2018 23:02:39 UTC+3, Spiros Bousbouras wrote:
>>> On Tue, 25 Sep 2018 03:19:39 -0700 (PDT)
>>> Tiib wrote:
>>>> Why there
>>>> are no standard way to check most of those implementation-defined
>>>> things compile-time?
>>>>
>>>> There are no standard way to check in code what is going on starting
>>>> from most mundane things like what is the encoding that compiler
>>>> expects the very code to be in and then continuing to endianness,
>>>> alignment, how signedness is represented &c.
>>>
>>> Why do you want to check these things during compilation?
>>
>> Because obviously all processing that is done during compilation has
>> zero run time cost.
>
> For the things you mentioned the checking can be done at programme start up
> and will increase the start up time by less than 1 microsecond. So I don't
> see it as a problem.
>

This is not about 1 盜 of run-time at startup. If you can determine
endianness at compile-time, you can use it for conditional compilation
to use different struct layouts matching endianness, or to choose
between different implementations of functions at compile time. Being
able to tell the endianness at compile time rather than run-time means a
function like "ntonl" (net-to-host endian change) is a nanosecond
faster. A single nanosecond makes little difference to a single
function call - but when the function is used dozens of times for every
network packet received, these nanoseconds add up very quickly.

_Static_assert() was also mentioned. Being able to check features at
compile-time, and give a compilation failure at the point of unfulfilled
expectations, is /vastly/ better than checking at run-time.


David Brown

unread,
Sep 27, 2018, 4:18:20 AM9/27/18
to
On 26/09/18 23:30, Bart wrote:
> On 26/09/2018 21:50, David Brown wrote:
>> On 26/09/18 19:09, Bart wrote:
>>> On 26/09/2018 16:30, David Brown wrote:
>>>> On 26/09/18 16:52, Malcolm McLean wrote:
>>>
>>>>> If we use ... to represent an infinite series
>>>>> rather than 8 on its side to represent infinity, we get a rather
>>>>> different
>>>>> mathematics. Maybe less powerful, but still valid.
>>>>>
>>>>
>>>> If you are using "..." to represent something other than infinity, then
>>>> it is not the same as infinity. Writing "...999" to mean "an infinite
>>>> sequence of 9's" gives you infinity. Writing ∞ is another very common
>>>> way of representing "infinity".
>>>>
>>>> Of course ellipsis can mean something other than "infinity" - it
>>>> usually
>>>> means that a pattern continues (either for a finite count, or
>>>> unendingly). But in this context, it meant infinity.
>>>
>>> In my posts I meant an endless sequence of 9s, /written right to
>>> left/. An infinite number of them, if you like. But not the value ∞.
>>>
>>
>> And endless sequence of 9's, regardless of which direction they are
>> written (the distinction makes no sense) is infinite.
>
> 'infinite' or 'infinity'?
>

What difference do /you/ think that makes?

> If you mean the latter, then no it doesn't. I have an infinite number of
> symbols (the digits 0 thru 9), to which I can ascribe any meaning I like.
>

At this point we are in Humpty-dumpty land. My notations mean exactly
what I want them to mean...

> And the direction is crucial, since we need to start at the least
> significant end.
>

Humpty-dumpty again.

I am sure it is possible to make a rigorous mathematics here, with clear
definitions and a consistent algebra on the structures you are
inventing. But if you are not using the same notation for the same
purpose as other people expect, then you cannot expect people to
understand what you mean or agree with you. And you certainly can't
expect anyone to think it is a useful way to help understand a far
simpler concept.

> Actually, we don't need an infinite number of digits to show the
> patterns, a finite number will do, except that I know have to say the
> numbers wrap.
>
> So your objections no longer matter.

If you stick to finite lengths and wrap your numbers, then you are back
to standard modulo arithmetic. This is established territory, familiar
to many people, and I entirely agree (and have said so) that doing this
in decimal can make it easier for people to understand two's complement
binary. It is not that "my objections no longer matter" - I would not
have any objections at all.

My objection is to your ideas about infinity and unending sequences of
digits, how you say that this makes normal integers wrap, that you play
fast and loose about which digits you think are important and which you
think can be ignored, and how you think this mess somehow "proves" that
you don't need a minus sign and that it explains two's complement.

Take away all your infinities and unending sequences, and we will be fine.

>
> That is what is
>> meant by the term "infinity" (unless you are dealing with more
>> advanced transfinite mathematics).
>>
>>> The value I had in mind was one less than zero.
>>>
>>
>> I realise that was in your mind. It bore no relation to what you wrote.
>
> You're not going to let this go are you?
>

Beneath your unending sequences with secret definitions, there is a far
simpler idea with fixed-length numbers and standard modulo arithmetic
that does exactly what you want. This gives you a decimal analogue to
two's complement that is clear, useful and correct.

Maybe we can settle on that?


Malcolm McLean

unread,
Sep 27, 2018, 5:53:35 AM9/27/18
to
You don't understand the situation. Mathematics cannot be separated from
the notation used for mathematics in that way.

David Brown

unread,
Sep 27, 2018, 6:19:13 AM9/27/18
to
You are wrong. Feel free to look up about infinity on the web, to see
if you can understand a little about it. Maybe you could talk to a
mathematician who could explain to you the difference between
mathematics and mathematical notation - it is much like the difference
between a C object's value and the representation used for it.

I will leave it at that, lest this turn into a pantomime.

Bart

unread,
Sep 27, 2018, 6:52:16 AM9/27/18
to
On 27/09/2018 09:18, David Brown wrote:
> On 26/09/18 23:30, Bart wrote:

>> 'infinite' or 'infinity'?
>>
>
> What difference do /you/ think that makes?

I understood that infinity refers to a number, a quantity.

That's subtly different from an infinite series of things. Like the
difference between:

7 - the number of 9s in 9999999, or the A's in AAAAAAA

and:

9,999,999 - the value of 9999999 interpreted as a decimal number

If you mean the latter, then no it doesn't. I have an infinite number of
>> symbols (the digits 0 thru 9), to which I can ascribe any meaning I like.
>>
>
> At this point we are in Humpty-dumpty land. My notations mean exactly
> what I want them to mean...

Which is pretty much how a lot of modern computing seems to be defined.

And especially in this group when talking about C.

> I am sure it is possible to make a rigorous mathematics here, with clear
> definitions and a consistent algebra on the structures you are
> inventing.

You don't need to take things that seriously to end up with useful,
practical results.

> Take away all your infinities and unending sequences, and we will be fine.

Let's call the number of digits unspecified then. Just much larger than
anyone would ever need for computer arithmetic. (No computing of values
like 3^^^^3.)

Remember that in my model, beyond a practical number of digits, we know
all digits to the left will be either all 0s, or all 9s. Then once we
know the first one of those is 0 or 1, it is not actually necessary to
compute all the rest; we can assume what they are.

>> You're not going to let this go are you?
>>
>
> Beneath your unending sequences with secret definitions, there is a far
> simpler idea with fixed-length numbers and standard modulo arithmetic
> that does exactly what you want. This gives you a decimal analogue to
> two's complement that is clear, useful and correct.
>
> Maybe we can settle on that?

OK, but what is the upper limit on the length of those numbers, at which
mathematics says it would stop working?


--
bart

James Kuyper

unread,
Sep 27, 2018, 7:12:27 AM9/27/18
to
Agreed, which would appear to be his point: he wants features similar to
that one added to C.

> Most compilers have pre-defined macros for endian determination, or the
> compiler is tied to a single target with fixed endianness. So there are
> headers available on the net that give you compile-time endian detection
> that works on a great proportion of compilers, simply by determining the
> compiler and using their specific symbols. It is not fully portable,
> but it may work well enough in practice.

He wants a standard-defined mechanism, so that it will be fully
portable, which seems to me to be an entirely reasonable thing to want.

David Brown

unread,
Sep 27, 2018, 7:45:00 AM9/27/18
to
On 27/09/18 12:52, Bart wrote:
> On 27/09/2018 09:18, David Brown wrote:
>> On 26/09/18 23:30, Bart wrote:
>
>>> 'infinite' or 'infinity'?
>>>
>>
>> What difference do /you/ think that makes?
>
> I understood that infinity refers to a number, a quantity.
>

"Infinity" is not a "number" in the normal sense. It does not have the
kinds of properties you normally associate with a number - adding and
subtracting one to it make no difference, for example. Subtracting it
from itself is meaningless. Sometimes a distinction is made between
positive and negative infinities, and it is possible to go into more
rigorous treatment of transfinite (or non-finite) "numbers" that
introduce even more complications. With finite non-negative integers,
there is a clear correlation between cardinals (i.e., size) and ordinals
(for ordering) - the number "6" is used for both a size and an ordering.
Once you get to infinite numbers, this breaks down. The first infinite
ordinal, omega 0 "ω₀", has different properties from the first infinite
cardinal, aleph 0 "ℵ₀". For example, ω₀ + 1 > ω₀ but 1 + ω₀ = ω₀, just
as ℵ₀ + 1 = ℵ₀. And you get different sizes of infinity - the size of
the set of integers is ℵ₀, as is the size of the set of rational numbers
- but the size of the set of real numbers is much bigger, being 2 ^ ℵ₀.
The complications and interesting features of these transfinite numbers
is, well, endless.

Very often, it is enough to simplify things and talk about "infinity"
with the symbol ∞ as an entity that is bigger than any finite number,
and for which the rules of maths don't apply. That is fine in most
contexts, as long as you don't try to do treat it as a number - it is
just an indication that something goes on without stopping.

> That's subtly different from an infinite series of things. Like the
> difference between:
>
> 7 - the number of 9s in 9999999, or the A's in AAAAAAA
>
> and:
>
> 9,999,999 - the value of 9999999 interpreted as a decimal number
>

An infinite series does not need to be "infinity". An obvious example
would be an infinite decimal - 0.333... is 1/3, not infinity. But the
number of digits is infinite.

A series of digits without a decimal point represents a single finite
integer if the number of digits is finite, or infinity if it the number
of digits is infinite (i.e., endless). In that case, it does not matter
what the digits are when considering the value of the number - being
infinite, it does not have a value in the conventional sense.

So for any positive integer n, a series of n 2's is always an even
number, and bigger than a series of n 1's. But for infinite series, it
does not make sense to say one is even and the other odd, or to make any
distinction between them.

> If you mean the latter, then no it doesn't. I have an infinite number of
>>> symbols (the digits 0 thru 9), to which I can ascribe any meaning I
>>> like.
>>>
>>
>> At this point we are in Humpty-dumpty land. My notations mean exactly
>> what I want them to mean...
>
> Which is pretty much how a lot of modern computing seems to be defined.

Of course all notation has been made up by someone at some point. I
don't mean your notation is necessarily inferior - merely that it is
personal to you alone (the rest of us just guess at it). Notation
becomes useful for communication when other people understand what it means.

>
> And especially in this group when talking about C.
>
>> I am sure it is possible to make a rigorous mathematics here, with clear
>> definitions and a consistent algebra on the structures you are
>> inventing.
>
> You don't need to take things that seriously to end up with useful,
> practical results.
>

Your unending series don't give practical results - they are meaningless
without rigorous definitions, and unnecessarily complex even if they
/had/ good definitions.

>> Take away all your infinities and unending sequences, and we will be
>> fine.
>
> Let's call the number of digits unspecified then. Just much larger than
> anyone would ever need for computer arithmetic. (No computing of values
> like 3^^^^3.)

No, let's not. Let's pick a number of digits that is big enough to show
the effect, but small enough to be convenient. Three digits would be nice.

Then when you have shown your examples with 3 digits, it's easy to say
"you can see how the pattern could be extended for bigger numbers - just
as with computer integer types, you can have 8-bits, 16-bits, or any
other fixed size type you like".

>
> Remember that in my model, beyond a practical number of digits, we know
> all digits to the left will be either all 0s, or all 9s. Then once we
> know the first one of those is 0 or 1, it is not actually necessary to
> compute all the rest; we can assume what they are.
>
>>> You're not going to let this go are you?
>>>
>>
>> Beneath your unending sequences with secret definitions, there is a far
>> simpler idea with fixed-length numbers and standard modulo arithmetic
>> that does exactly what you want. This gives you a decimal analogue to
>> two's complement that is clear, useful and correct.
>>
>> Maybe we can settle on that?
>
> OK, but what is the upper limit on the length of those numbers, at which
> mathematics says it would stop working?
>

There is no /finite/ limit - no single integer which is the biggest
integer. The mathematics of integers stops working when you try to go
beyond the finite.

David Brown

unread,
Sep 27, 2018, 8:05:12 AM9/27/18
to
Yes. Something like gcc's macros would be more useful if standardised :

__BYTE_ORDER__
__ORDER_LITTLE_ENDIAN__
__ORDER_BIG_ENDIAN__
__ORDER_PDP_ENDIAN__

/* Test for a little-endian machine */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
...

Perhaps the "PDP Endian" could be dropped, and the next C standard could
say these macros shall be defined if and only if the byte order is big
or little endian.

The exact names here don't matter too much - it is the consistency that
matters. Probably if this were to be in the C standards, a __STDC_
prefix to the names would be appropriate.




Richard Damon

unread,
Sep 27, 2018, 8:27:04 AM9/27/18
to
I would say that trying to talk about a numeric representation that has
an infinite number of increasingly significant digits is a poorly
defined concept in Standard Mathematics.

Note, that is a different statement than talking about a number ...999
where the ... refers to an arbitrarily large and indefinite number of
digits. Standard Mathematics can talk about such number.

One issue with an infinite number of leading significant digits is that
you can't even attempt to get meaning via limit theory, as the
difference between the incremental stages and the final number is
infinite, and thus doesn't decrease.

If you want to try to talk about ...999 as an infinitely long number and
being a different number than ...998 you are going to have to
specify/develop a mathematics that can talk about such numbers and
figure out what properties you can discuss about such numbers. It is
probably possible to develop such a mathematics where ...999 is
congruent to -1, but such probably falls out as a definition, not a
conclusion (similar to treating an infinite chain of leading 1s in a
binary notation as negative).

For ... representing an arbitrary and possibly indefinite string of
digits, as long as you assume that ...999 is a distinct number from
09...999, then it is easy to define that ...999 is congruent to -1 using
a 10's complement decimal notation. It is also possible to define ...998
as -1 and ...999 as -0 using 9's complement decimal notation (similar to
2's complement and 1's complement binary representations).


jadi...@gmail.com

unread,
Sep 27, 2018, 9:25:47 AM9/27/18
to
On Thursday, September 27, 2018 at 3:53:13 AM UTC-4, David Brown wrote:
You can also have a build system compile and run a sample code fragment that
tests for endianness that translates the result into a #define in a config.h
file.

Geoff

unread,
Sep 27, 2018, 9:30:46 AM9/27/18
to
On Thu, 27 Sep 2018 06:25:31 -0700 (PDT), jadi...@gmail.com wrote:

>You can also have a build system compile and run a sample code fragment that
>tests for endianness that translates the result into a #define in a config.h
>file.

How would that work when the target system is not the development
system?

David Brown

unread,
Sep 27, 2018, 10:05:42 AM9/27/18
to
You can, but that is only useful for native compilation - it will not
help for code compiled for a different target than the host.
Cross-compilation is common for C code. In addition, it will also
complicate the build process.


Robert Wessel

unread,
Sep 27, 2018, 10:37:22 AM9/27/18
to
On Wed, 26 Sep 2018 16:53:59 +0200, David Brown
<david...@hesbynett.no> wrote:

>On 26/09/18 16:49, Malcolm McLean wrote:
>> On Wednesday, September 26, 2018 at 3:03:11 PM UTC+1, David Brown wrote:
>>>
>>> You will get on far better by taking a clock, putting a "0" sticker over
>>> the "12", and looking at adding and subtracting hours on that.
>>>
>> Many a true word spoken in jest.
>
>What jest? Clocks are a good way to learn about modulo arithmetic, and
>modulo arithmetic is what you need for understanding two's complement.


When I learned about modular arithmetic in junior high (far longer ago
than I care to recall), the textbook actually introduced the concept
as "clock arithmetic".

jadi...@gmail.com

unread,
Sep 27, 2018, 11:33:45 AM9/27/18
to
On Thursday, September 27, 2018 at 9:30:46 AM UTC-4, Geoff wrote:
> On Thu, 27 Sep 2018 06:25:31 -0700 (PDT), j...@gmail.com wrote:
>
> >You can also have a build system compile and run a sample code fragment that
> >tests for endianness that translates the result into a #define in a config.h
> >file.
>
> How would that work when the target system is not the development
> system?

It wouldn't.

luser droog

unread,
Sep 27, 2018, 7:53:37 PM9/27/18
to
On Thursday, September 27, 2018 at 6:12:27 AM UTC-5, James Kuyper wrote:
> He wants a standard-defined mechanism, so that it will be fully


Apropos of nothing, upon first glance I thought this said "standard-
defined masochism" and had quite a chuckle.

Carry on.

James Kuyper

unread,
Sep 27, 2018, 7:59:47 PM9/27/18
to
You'd have to transport the compiled and linked source code fragment to
the target system, run it to create the config.h file, and then
transport the resulting config.h file back to the system where the rest
of the compilation will be done. It's not particularly convenient, but
it is doable.

luser droog

unread,
Sep 27, 2018, 8:04:59 PM9/27/18
to
On Thursday, September 27, 2018 at 7:27:04 AM UTC-5, Richard Damon wrote:
> On 9/26/18 1:09 PM, Bart wrote:
> > On 26/09/2018 16:30, David Brown wrote:
> >> On 26/09/18 16:52, Malcolm McLean wrote:
> >
> >>> If we use ... to represent an infinite series
> >>> rather than 8 on its side to represent infinity, we get a rather
> >>> different
> >>> mathematics. Maybe less powerful, but still valid.
> >>>
> >>
> >> If you are using "..." to represent something other than infinity, then
> >> it is not the same as infinity.  Writing "...999" to mean "an infinite
> >> sequence of 9's" gives you infinity.  Writing ∞ is another very common
> >> way of representing "infinity".
> >>
> >> Of course ellipsis can mean something other than "infinity" - it usually
> >> means that a pattern continues (either for a finite count, or
> >> unendingly).  But in this context, it meant infinity.
> >
> > In my posts I meant an endless sequence of 9s, /written right to left/.
> > An infinite number of them, if you like. But not the value ∞.
> >
> > The value I had in mind was one less than zero.
> >
>
> I would say that trying to talk about a numeric representation that has
> an infinite number of increasingly significant digits is a poorly
> defined concept in Standard Mathematics.
>

There is something kind of like this with the Quote Notation for p-adics.
To veer somewhat toward topicality, references for QN and p-adics are in
my SO question.

https://stackoverflow.com/questions/32529118/incorporate-repetition-detection-in-my-p-adic-arithmetic-loops

--
the whole endeavor was a bust, alas

Robert Wessel

unread,
Sep 27, 2018, 8:58:48 PM9/27/18
to
Always assuming the target system has the ability to create a file.

Ben Bacarisse

unread,
Sep 27, 2018, 11:44:55 PM9/27/18
to
David Brown <david...@hesbynett.no> writes:
<snip>
> Your unending series don't give practical results - they are meaningless
> without rigorous definitions, and unnecessarily complex even if they
> /had/ good definitions.

Imagine a student is writing the standard integer to decimal function.
They print n 'div' 10 in front of n 'mod' 10. This is simplest written
with an auxiliary recursive function:

def pn(n):
def pn_aux(n):
pn_aux(n // 10)
print(chr(ord('0') + n % 10), end='')
pn_aux(n)
print('')

(That it's Python is important -- Python has mod (%) and integer divide
(//) that make more sense in a mathematical context.)

Obviously they find that the function loops. To stop this, the
enterprising student passes another argument so as to print "..." when
the number being printed is the same as in the last call:

def pn(n):
def pn_aux(n, last_n):
if n == last_n:
print("...", end='')
else:
pn_aux(n // 10, n)
print(chr(ord('0') + n % 10), end='')
pn_aux(n, None)
print('')

Trying it out they see:
>>> pn(0)
...0
>>> pn(10)
...010
>>> pn(-1)
...9
>>> pn(-2)
...98
>>> pn(-10)
...90

and they see that it makes perfect sense as "all the nines" (...9) is
obviously "one back" from all the zeros, (...0).

Knowing a bit about 2's complement, and that Python has unbounded
integers ("big nums") the curious students wants to see if this language
appears to have infinitely many bits for an integer. They try this:

>>> (-1 >> 1000) % 2
1
>>> (-1 >> 100000) % 2
1
>>> (-1 >> 10000000000) % 2
1

It certainly seems like there are infinitely many 1 bits in -1 since
they can find no shift of that does not give a 1.

<snip>
--
Ben.

Richard Damon

unread,
Sep 28, 2018, 7:53:49 AM9/28/18
to
Yes, a number of my targets are small enough not to have filesystems, or
even the memory to create one (They are 'Stand-alone' not 'Hosted'
environments.
It is loading more messages.
0 new messages