Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #97397 > unrolled thread

Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable?

Started byFrancois Grieu <fgrieu@free.fr>
First post2016-11-24 15:33 +0100
Last post2016-11-24 07:40 -0800
Articles 20 on this page of 27 — 9 participants

Back to article view | Back to comp.lang.c


Contents

  Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Francois Grieu <fgrieu@free.fr> - 2016-11-24 15:33 +0100
    Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-24 14:59 +0000
      Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Francois Grieu <fgrieu@free.fr> - 2016-11-24 18:34 +0100
        Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? supercat@casperkitty.com - 2016-11-24 14:03 -0800
        Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? David Brown <david.brown@hesbynett.no> - 2016-11-25 09:50 +0100
      Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Noob <root@127.0.0.1> - 2016-11-25 09:44 +0100
        Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? David Brown <david.brown@hesbynett.no> - 2016-11-25 11:14 +0100
          Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-25 11:12 +0000
            Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? supercat@casperkitty.com - 2016-11-25 10:50 -0800
              Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Keith Thompson <kst-u@mib.org> - 2016-11-25 12:12 -0800
                Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Nick Bowler <nbowler@draconx.ca> - 2016-11-25 21:45 +0000
                Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? supercat@casperkitty.com - 2016-11-25 13:58 -0800
                  Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Keith Thompson <kst-u@mib.org> - 2016-11-28 23:37 -0800
                    Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-29 12:01 +0000
                    Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? supercat@casperkitty.com - 2016-11-29 07:39 -0800
                      Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Keith Thompson <kst-u@mib.org> - 2016-11-29 09:12 -0800
                Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-25 22:54 +0000
            Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Nick Bowler <nbowler@draconx.ca> - 2016-11-25 22:01 +0000
              Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-11-25 23:22 +0000
                Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Tim Rentsch <txr@alumni.caltech.edu> - 2016-12-10 07:22 -0800
      Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Tim Rentsch <txr@alumni.caltech.edu> - 2016-12-01 10:16 -0800
        Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Barry Schwarz <schwarzb@dqel.com> - 2016-12-01 11:06 -0800
          Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? supercat@casperkitty.com - 2016-12-01 12:40 -0800
          Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? David Brown <david.brown@hesbynett.no> - 2016-12-02 09:28 +0100
          Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? Tim Rentsch <txr@alumni.caltech.edu> - 2016-12-10 07:13 -0800
            Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? supercat@casperkitty.com - 2016-12-10 10:41 -0800
    Re: Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable? supercat@casperkitty.com - 2016-11-24 07:40 -0800

Page 1 of 2  [1] 2  Next page →


#97397 — Is uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable?

FromFrancois Grieu <fgrieu@free.fr>
Date2016-11-24 15:33 +0100
SubjectIs uint32_t foo(uint32_t x) { return (uint32_t)(x*x); } portable?
Message-ID<5836fa81$0$4275$426a74cc@news.free.fr>
Assume this code, under C99 or later


#include <stdint.h>
uint32_t foo(uint32_t x) { return (uint32_t)(x*x); }

Is the return value of foo well defined for any uint32_t input?


In particular: when int is 64-bit, x gets promoted to int and becomes signed, 
and x*x can overflow the range of int; e.g. for x=(uint32_t)(-1);
So, what chapter and verse (if any) saves the day?

TIA,
   Francois Grieu

[toc] | [next] | [standalone]


#97398

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-11-24 14:59 +0000
Message-ID<87wpfsvs8p.fsf@bsb.me.uk>
In reply to#97397
Francois Grieu <fgrieu@free.fr> writes:

> Assume this code, under C99 or later
>
> #include <stdint.h>
> uint32_t foo(uint32_t x) { return (uint32_t)(x*x); }

The cast is pointless.  The returned value is always converted to the
return type of the function.

> Is the return value of foo well defined for any uint32_t input?

No, for the reasons you go on to explain

> In particular: when int is 64-bit, x gets promoted to int and becomes
> signed, and x*x can overflow the range of int; e.g. for
> x=(uint32_t)(-1);
> So, what chapter and verse (if any) saves the day?

  uint32_t foo(uint32_t x) { return 1u * x * x; }

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#97408

FromFrancois Grieu <fgrieu@free.fr>
Date2016-11-24 18:34 +0100
Message-ID<583724fa$0$24786$426a74cc@news.free.fr>
In reply to#97398
On 24/11/2016 à 15:59, Ben Bacarisse wrote:

> Francois Grieu <fgrieu@free.fr> writes:
>
>> Assume this code, under C99 or later
>>
>> #include <stdint.h>
>> uint32_t foo(uint32_t x) { return (uint32_t)(x*x); }
>
> The cast is pointless.  The returned value is always converted to the
> return type of the function.

Indeed; cast was intended to avoid a warning by some overzealous compiler.

>> Is the return value of foo well defined for any uint32_t input?
>
> No, for the reasons you go on to explain

Thanks. Thus the product of two uintn_t (for any n>=8) is undefined even in the 
low-order n bits of the result. <OT>I wonder where it really is so!!</OT>.


>> So, what chapter and verse (if any) saves the day?
>
>   uint32_t foo(uint32_t x) { return 1u * x * x; }

Right.


My actual code (at http://crypto.stackexchange.com/a/33261/555 ) was

#include <stdint.h>                     // for uint64_t and uint32_t

// given odd a, compute x such that a*x = 1 over 64 bits.
uint64_t invmod(uint64_t a)
     {
     uint32_t b = (uint32_t)a;           // low 32 bits of a
     uint32_t x = (((b+2u)&4u)<<1)+b;    // low  4 bits of inverse
     x =    (2u-b*x)*x;                  // low  8 bits of inverse
     x =    (2u-b*x)*x;                  // low 16 bits of inverse
     x =    (2u-b*x)*x;                  // low 32 bits of inverse
     return (2u-a*x)*x;                  //     64 bits of inverse
     }


<OT>I wonder how to best to make it correct in a context NOT dedicated to the 
intricacies of the C standard; I'm ready to ditch performance optimization on 
32-bit platforms (my motivation for introducing b).</OT>

   Francois Grieu

[toc] | [prev] | [next] | [standalone]


#97427

Fromsupercat@casperkitty.com
Date2016-11-24 14:03 -0800
Message-ID<0e351760-6d6e-40ee-8c6f-b5f6dc00110a@googlegroups.com>
In reply to#97408
On Thursday, November 24, 2016 at 11:36:04 AM UTC-6, Francois Grieu wrote:
> <OT>I wonder how to best to make it correct in a context NOT dedicated to the 
> intricacies of the C standard; I'm ready to ditch performance optimization on 
> 32-bit platforms (my motivation for introducing b).</OT>

You could test what effect -fwrapv would have on performance, perhaps
comparing code generation with and without that flag to look for chances
to help let the compiler make the optimizations it would make with -fwrapv
even when the flag isn't enabled.

If code which achieves good performance with -fwrapv is cleaner than code
that achieve comparable performance without it, I'd suggest simply
documenting that your code is only usable with compilers that handle
overflow in at least somewhat-sensible fashion.  Semantics wouldn't need
to be as precise as those implied by -fwrapv, but depending upon what your
code is doing the penalty from -fwrapv may or may not be a problem.

[toc] | [prev] | [next] | [standalone]


#97448

FromDavid Brown <david.brown@hesbynett.no>
Date2016-11-25 09:50 +0100
Message-ID<o18tuh$e56$1@dont-email.me>
In reply to#97408
On 24/11/16 18:34, Francois Grieu wrote:
> On 24/11/2016 à 15:59, Ben Bacarisse wrote:
> 
>> Francois Grieu <fgrieu@free.fr> writes:
>>
>>> Assume this code, under C99 or later
>>>
>>> #include <stdint.h>
>>> uint32_t foo(uint32_t x) { return (uint32_t)(x*x); }
>>
>> The cast is pointless.  The returned value is always converted to the
>> return type of the function.
> 
> Indeed; cast was intended to avoid a warning by some overzealous compiler.
> 
>>> Is the return value of foo well defined for any uint32_t input?
>>
>> No, for the reasons you go on to explain
> 
> Thanks. Thus the product of two uintn_t (for any n>=8) is undefined even
> in the low-order n bits of the result. <OT>I wonder where it really is
> so!!</OT>.
> 
> 
>>> So, what chapter and verse (if any) saves the day?
>>
>>   uint32_t foo(uint32_t x) { return 1u * x * x; }
> 
> Right.
> 
> 
> My actual code (at http://crypto.stackexchange.com/a/33261/555 ) was
> 
> #include <stdint.h>                     // for uint64_t and uint32_t
> 
> // given odd a, compute x such that a*x = 1 over 64 bits.
> uint64_t invmod(uint64_t a)
>     {
>     uint32_t b = (uint32_t)a;           // low 32 bits of a
>     uint32_t x = (((b+2u)&4u)<<1)+b;    // low  4 bits of inverse
>     x =    (2u-b*x)*x;                  // low  8 bits of inverse
>     x =    (2u-b*x)*x;                  // low 16 bits of inverse
>     x =    (2u-b*x)*x;                  // low 32 bits of inverse
>     return (2u-a*x)*x;                  //     64 bits of inverse
>     }
> 
> 
> <OT>I wonder how to best to make it correct in a context NOT dedicated
> to the intricacies of the C standard; I'm ready to ditch performance
> optimization on 32-bit platforms (my motivation for introducing b).</OT>
> 
>   Francois Grieu

Note that even on 64-bit platforms, "int" is usually 32-bit.  There are
very few platforms with 64-bit int.  So it might be reasonable to write
your code like this :

#if UINT_MAX == 0xffffffff
uint64_t invmod(uint64_t a) {
	// Code optimised for 32-bit int
}
#else
#error Support for 16-bit, 64-bit, or weird int size not yet written
#endif

Then you can assume things like multiplying two uint32_t objects will
not reach undefined behaviour.

[toc] | [prev] | [next] | [standalone]


#97447

FromNoob <root@127.0.0.1>
Date2016-11-25 09:44 +0100
Message-ID<o18tj3$d04$1@dont-email.me>
In reply to#97398
On 24/11/2016 15:59, Ben Bacarisse wrote:

> Francois Grieu writes:
> 
>> Assume this code, under C99 or later
>>
>> #include <stdint.h>
>> uint32_t foo(uint32_t x) { return (uint32_t)(x*x); }
> 
> The cast is pointless.  The returned value is always converted to the
> return type of the function.
> 
>> Is the return value of foo well defined for any uint32_t input?
> 
> No, for the reasons you go on to explain
> 
>> In particular: when int is 64-bit, x gets promoted to int and becomes
>> signed, and x*x can overflow the range of int; e.g. for
>> x=(uint32_t)(-1);
>> So, what chapter and verse (if any) saves the day?
> 
>   uint32_t foo(uint32_t x) { return 1u * x * x; }

The standard states: "The rank of any unsigned integer type shall
equal the rank of the corresponding signed integer type, if any."

So 'int' and 'unsigned int' have the same "rank", whatever their
actual size?

Integer promotion is applied to "an object or expression with an
integer type whose integer conversion rank is less than or equal
to the rank of int and unsigned int. If an int can represent all
values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int."

Assuming a perverse implementation where
- int is 64 bits
- unsigned int is 32 bits
(Is that allowed?)

In such an implementation, 1u would be promoted to int for an
arithmetic operation, right? (Because int could represent all
values of unsigned int.)

One would have to write 1ull * x * x;

Regards.

[toc] | [prev] | [next] | [standalone]


#97454

FromDavid Brown <david.brown@hesbynett.no>
Date2016-11-25 11:14 +0100
Message-ID<o192rl$tok$1@dont-email.me>
In reply to#97447
On 25/11/16 09:44, Noob wrote:
> On 24/11/2016 15:59, Ben Bacarisse wrote:
> 
>> Francois Grieu writes:
>>
>>> Assume this code, under C99 or later
>>>
>>> #include <stdint.h>
>>> uint32_t foo(uint32_t x) { return (uint32_t)(x*x); }
>>
>> The cast is pointless.  The returned value is always converted to the
>> return type of the function.
>>
>>> Is the return value of foo well defined for any uint32_t input?
>>
>> No, for the reasons you go on to explain
>>
>>> In particular: when int is 64-bit, x gets promoted to int and becomes
>>> signed, and x*x can overflow the range of int; e.g. for
>>> x=(uint32_t)(-1);
>>> So, what chapter and verse (if any) saves the day?
>>
>>   uint32_t foo(uint32_t x) { return 1u * x * x; }
> 
> The standard states: "The rank of any unsigned integer type shall
> equal the rank of the corresponding signed integer type, if any."
> 
> So 'int' and 'unsigned int' have the same "rank", whatever their
> actual size?
> 
> Integer promotion is applied to "an object or expression with an
> integer type whose integer conversion rank is less than or equal
> to the rank of int and unsigned int. If an int can represent all
> values of the original type, the value is converted to an int;
> otherwise, it is converted to an unsigned int."
> 
> Assuming a perverse implementation where
> - int is 64 bits
> - unsigned int is 32 bits
> (Is that allowed?)

That is not allowed, so there is no problem :-)

6.2.5p6:

For each of the signed integer types, there is a corresponding (but
different) unsigned integer type (designated with the keyword unsigned)
that uses the same amount of storage (including sign information) and
has the same alignment requirements.

6.2.5p9:

The range of nonnegative values of a signed integer type is a subrange
of the corresponding unsigned integer type, and the representation of
the same value in each type is the same.




> 
> In such an implementation, 1u would be promoted to int for an
> arithmetic operation, right? (Because int could represent all
> values of unsigned int.)
> 
> One would have to write 1ull * x * x;
> 
> Regards.
> 

[toc] | [prev] | [next] | [standalone]


#97455

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-11-25 11:12 +0000
Message-ID<871sxz7qzw.fsf@bsb.me.uk>
In reply to#97454
David Brown <david.brown@hesbynett.no> writes:

> On 25/11/16 09:44, Noob wrote:
>> On 24/11/2016 15:59, Ben Bacarisse wrote:
>> 
>>> Francois Grieu writes:
>>>
>>>> Assume this code, under C99 or later
>>>>
>>>> #include <stdint.h>
>>>> uint32_t foo(uint32_t x) { return (uint32_t)(x*x); }
>>>
>>> The cast is pointless.  The returned value is always converted to the
>>> return type of the function.
>>>
>>>> Is the return value of foo well defined for any uint32_t input?
>>>
>>> No, for the reasons you go on to explain
>>>
>>>> In particular: when int is 64-bit, x gets promoted to int and becomes
>>>> signed, and x*x can overflow the range of int; e.g. for
>>>> x=(uint32_t)(-1);
>>>> So, what chapter and verse (if any) saves the day?
>>>
>>>   uint32_t foo(uint32_t x) { return 1u * x * x; }
>> 
>> The standard states: "The rank of any unsigned integer type shall
>> equal the rank of the corresponding signed integer type, if any."
>> 
>> So 'int' and 'unsigned int' have the same "rank", whatever their
>> actual size?

Yup.

>> Integer promotion is applied to "an object or expression with an
>> integer type whose integer conversion rank is less than or equal
>> to the rank of int and unsigned int. If an int can represent all
>> values of the original type, the value is converted to an int;
>> otherwise, it is converted to an unsigned int."

It's not 100% clear if this is supposed to apply to unsigned int when
int has the same positive range.  I'm not sure but I lean towards not.
Why mention unsigned int if the objects in question were not supposed to
exclude them?  Implementations where unsigned promotes to int would be
pathological in some senses.

>> Assuming a perverse implementation where
>> - int is 64 bits
>> - unsigned int is 32 bits
>> (Is that allowed?)
>
> That is not allowed, so there is no problem :-)

Right, but int and unsigned int might have the same range of positive
values.  So (putting uint32_t aside for the for the moment), 1u would
promote to int in some interpretations of the paragraph Noob quoted.  In
effect, you could not do unsigned arithmetic without forcing the use of
some type with higher conversion rank than int.

<snip>

As suggested here:

>> One would have to write 1ull * x * x;

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#97474

Fromsupercat@casperkitty.com
Date2016-11-25 10:50 -0800
Message-ID<e6af8d35-de73-4893-ace7-eb617a805475@googlegroups.com>
In reply to#97455
On Friday, November 25, 2016 at 5:12:34 AM UTC-6, Ben Bacarisse wrote:
> It's not 100% clear if this is supposed to apply to unsigned int when
> int has the same positive range.  I'm not sure but I lean towards not.
> Why mention unsigned int if the objects in question were not supposed to
> exclude them?  Implementations where unsigned promotes to int would be
> pathological in some senses.

Implementations where every unsigned value is representable as "int" are
hardly pathological. That would actually be a common state of affairs in
sign-magnitude or ones'-complement implementations.  If e.g. an 18-bit
ones'-complement platform could efficiently handle arithmetic mod 262,144
there would be little reason for a C compiler targeting that platform not
to use two's-complement arithmetic.  If, however, registers were incapable
of holding a value which had all the bits set, the only way to make
two's-complement or unsigned arithmetic work at all would be to treat the
upper bit as padding.  The costs associated with that would be unavoidable
with unsigned arithmetic, but could be avoided by using ones'-complement
notation for signed types.

On the other hand, if the type "unsigned int" promoted to "int", that
would render meaningless the guarantee that arithmetic on "unsigned int"
wraps with a power-of-two modulus, since there would be no way to
perform arithmetic on that type.

[toc] | [prev] | [next] | [standalone]


#97475

FromKeith Thompson <kst-u@mib.org>
Date2016-11-25 12:12 -0800
Message-ID<lnfumfb9p0.fsf@kst-u.example.com>
In reply to#97474
supercat@casperkitty.com writes:
> On Friday, November 25, 2016 at 5:12:34 AM UTC-6, Ben Bacarisse wrote:
>> It's not 100% clear if this is supposed to apply to unsigned int when
>> int has the same positive range.  I'm not sure but I lean towards not.
>> Why mention unsigned int if the objects in question were not supposed to
>> exclude them?  Implementations where unsigned promotes to int would be
>> pathological in some senses.
>
> Implementations where every unsigned value is representable as "int" are
> hardly pathological.

I won't argue the meaning of the word "pathological", but such
implementations are certainly rare.

>                      That would actually be a common state of affairs in
> sign-magnitude or ones'-complement implementations.

I've never used a sign-and-magnitude or ones'-complement implementation,
but I'd expect such an implementation to use all the bits of a word for
both signed and unsigned types.  For example, if int and unsigned int
are, say, 16 bits wide, I'd expect that most likely int would have a
range of -32767..+32767, and unsigned int to have a range of 0..65535.
Certainly there are other possibilities, including ones where the range
of unsigned int matches the non-negative subrange of int, but I'd expect
that to be unusual, perhaps even nonexistent.

Do you have a concrete example, or are you just speculating?

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@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"

[toc] | [prev] | [next] | [standalone]


#97482

FromNick Bowler <nbowler@draconx.ca>
Date2016-11-25 21:45 +0000
Message-ID<o1abdv$545$1@dont-email.me>
In reply to#97475
On Fri, 25 Nov 2016 12:12:27 -0800, Keith Thompson wrote:
> supercat@casperkitty.com writes:
>> That would actually be a common state of affairs in
>> sign-magnitude or ones'-complement implementations.
> 
> I've never used a sign-and-magnitude or ones'-complement implementation,
> but I'd expect such an implementation to use all the bits of a word for
> both signed and unsigned types.  For example, if int and unsigned int
> are, say, 16 bits wide, I'd expect that most likely int would have a
> range of -32767..+32767, and unsigned int to have a range of 0..65535.
> Certainly there are other possibilities, including ones where the range
> of unsigned int matches the non-negative subrange of int, but I'd expect
> that to be unusual, perhaps even nonexistent.
> 
> Do you have a concrete example, or are you just speculating?

I don't have a specific C implementation in mind, but suppose we wanted
to implement C on a target which does not actually provide any direct
support for integer arithmetic, but does support binary floating point

It might be reasonable on such a target to implement all C integers
(other than char and friends) using denormalized floating point
representations.  A straightforward implementation in this manner
would result in unsigned types whose range is a proper subset of the
corresponding signed type.

[toc] | [prev] | [next] | [standalone]


#97483

Fromsupercat@casperkitty.com
Date2016-11-25 13:58 -0800
Message-ID<c808ca65-c717-4c0f-96c2-2e84911e5195@googlegroups.com>
In reply to#97475
On Friday, November 25, 2016 at 2:11:17 PM UTC-6, Keith Thompson wrote:
> supercat writes:
> > Implementations where every unsigned value is representable as "int" are
> > hardly pathological.
> 
> I won't argue the meaning of the word "pathological", but such
> implementations are certainly rare.

I certainly won't dispute that.

> >                      That would actually be a common state of affairs in
> > sign-magnitude or ones'-complement implementations.
> 
> I've never used a sign-and-magnitude or ones'-complement implementation,
> but I'd expect such an implementation to use all the bits of a word for
> both signed and unsigned types.  For example, if int and unsigned int
> are, say, 16 bits wide, I'd expect that most likely int would have a
> range of -32767..+32767, and unsigned int to have a range of 0..65535.
> Certainly there are other possibilities, including ones where the range
> of unsigned int matches the non-negative subrange of int, but I'd expect
> that to be unusual, perhaps even nonexistent.
> 
> Do you have a concrete example, or are you just speculating?

  http://public.support.unisys.com/2200/docs/cp14.0/pdf/78310422-011.pdf

I don't know exactly how such hardware works, but I would expect that since
the compiler achieves conformance by looping off a bit, that would imply that
having an unsigned type support all 36 bits would be difficult.

Incidentally, I'm also curious about whether the actual range of the
"long long" type is +/-(2^71-1), or whether that's merely the range that
the documentation guarantees will work.  Unless the instruction set is
really weird I can't imagine it having the instructions that would be
needed to allow efficient math on a one's-complement values that are stored
in two words each.  In a two's-complement system, it's possible to add the
lower half of each value and then the upper half, bringing along a single
carry bit.  In ones'-complement math, both halves of the number interact
with each other in more complicated ways.  I can think of ways of handling
multi-word math that ones'-complement hardware might be able to handle more
efficiently than it could handle two's-complement, but I can't think of any
efficient way by which a ones'-complement platform could handle multi-word
math on ones'-complement values.

[toc] | [prev] | [next] | [standalone]


#97711

FromKeith Thompson <kst-u@mib.org>
Date2016-11-28 23:37 -0800
Message-ID<ln4m2qag9n.fsf@kst-u.example.com>
In reply to#97483
supercat@casperkitty.com writes:
> On Friday, November 25, 2016 at 2:11:17 PM UTC-6, Keith Thompson wrote:
>> supercat writes:
>> > Implementations where every unsigned value is representable as "int" are
>> > hardly pathological.
>> 
>> I won't argue the meaning of the word "pathological", but such
>> implementations are certainly rare.
>
> I certainly won't dispute that.
>
>> >                      That would actually be a common state of affairs in
>> > sign-magnitude or ones'-complement implementations.
>> 
>> I've never used a sign-and-magnitude or ones'-complement implementation,
>> but I'd expect such an implementation to use all the bits of a word for
>> both signed and unsigned types.  For example, if int and unsigned int
>> are, say, 16 bits wide, I'd expect that most likely int would have a
>> range of -32767..+32767, and unsigned int to have a range of 0..65535.
>> Certainly there are other possibilities, including ones where the range
>> of unsigned int matches the non-negative subrange of int, but I'd expect
>> that to be unusual, perhaps even nonexistent.
>> 
>> Do you have a concrete example, or are you just speculating?
>
>   http://public.support.unisys.com/2200/docs/cp14.0/pdf/78310422-011.pdf

Thank you for posting that.

> I don't know exactly how such hardware works, but I would expect that since
> the compiler achieves conformance by looping off a bit, that would imply that
> having an unsigned type support all 36 bits would be difficult.

(The link is to a download page, not to the actual PDF.)

I think you've misread it.

(Not relevant to the point, but section 4.3 treats "plain integers" and
"signed integers" as distinct, which is nonsense.)

For example, int and unsigned int are both 36 bits.  The range of int is
shown as -2**35+1 to +2**35-1, and range of unsigned int as 0 to
2**36-2.  (There's a conformance option that makes the upper bound of
unsigned int 2**36-1.)

It doesn't lop off a bit for unsigned types, it lops of a single value.
(I don't know why, but I haven't given it much thought.)

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@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"

[toc] | [prev] | [next] | [standalone]


#97725

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-11-29 12:01 +0000
Message-ID<8737iah4uv.fsf@bsb.me.uk>
In reply to#97711
Keith Thompson <kst-u@mib.org> writes:

> supercat@casperkitty.com writes:
>> On Friday, November 25, 2016 at 2:11:17 PM UTC-6, Keith Thompson wrote:
>>> supercat writes:
>>> > Implementations where every unsigned value is representable as "int" are
>>> > hardly pathological.
>>> 
>>> I won't argue the meaning of the word "pathological", but such
>>> implementations are certainly rare.
>>
>> I certainly won't dispute that.
>>
>>> >                      That would actually be a common state of affairs in
>>> > sign-magnitude or ones'-complement implementations.
>>> 
>>> I've never used a sign-and-magnitude or ones'-complement implementation,
>>> but I'd expect such an implementation to use all the bits of a word for
>>> both signed and unsigned types.  For example, if int and unsigned int
>>> are, say, 16 bits wide, I'd expect that most likely int would have a
>>> range of -32767..+32767, and unsigned int to have a range of 0..65535.
>>> Certainly there are other possibilities, including ones where the range
>>> of unsigned int matches the non-negative subrange of int, but I'd expect
>>> that to be unusual, perhaps even nonexistent.
>>> 
>>> Do you have a concrete example, or are you just speculating?
>>
>>   http://public.support.unisys.com/2200/docs/cp14.0/pdf/78310422-011.pdf
>
> Thank you for posting that.
>
>> I don't know exactly how such hardware works, but I would expect that since
>> the compiler achieves conformance by looping off a bit, that would imply that
>> having an unsigned type support all 36 bits would be difficult.
>
> (The link is to a download page, not to the actual PDF.)
>
> I think you've misread it.
>
> (Not relevant to the point, but section 4.3 treats "plain integers" and
> "signed integers" as distinct, which is nonsense.)
>
> For example, int and unsigned int are both 36 bits.  The range of int is
> shown as -2**35+1 to +2**35-1, and range of unsigned int as 0 to
> 2**36-2.  (There's a conformance option that makes the upper bound of
> unsigned int 2**36-1.)

There is another Unisys C implementation that is an example of the
problem.  It has 40 bits types and int can store all the values of
unsigned int.  In effect there is a padding bit in the unsigned types
(except for unsigned char).  I suspect this is because it uses floating
point hardware to do all arithmetic, but that's just a guess.

https://public.support.unisys.com/aseries/docs/clearpath-mcp-16.0/pdf/86002268-205.pdf

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#97735

Fromsupercat@casperkitty.com
Date2016-11-29 07:39 -0800
Message-ID<06ca061a-9d48-4206-ad63-d8e6b8e76768@googlegroups.com>
In reply to#97711
On Tuesday, November 29, 2016 at 1:36:09 AM UTC-6, Keith Thompson wrote:
> For example, int and unsigned int are both 36 bits.  The range of int is
> shown as -2**35+1 to +2**35-1, and range of unsigned int as 0 to
> 2**36-2.  (There's a conformance option that makes the upper bound of
> unsigned int 2**36-1.)

Hmm... I'd read of a machine whose conformance option lopped it to 2**35-1;
I thought it was the same one, but it must have been a different one.  A
value of 2**36-2 is non-conforming; either 2**35-1 or 2**36-1 would be
conforming, but hardware always adds 1 to any 36-bit arithmetic result which
is greater than 2**36-2, having UINT_MAX be 2**35-1 might be a lot cheaper
than having it be 2**36-1.  The sum of two unsigned values would simply be:

    result = (value1 + value2) & 0x7FFFFFFFF;

If the system can't handle arithmetic that could yield 0xFFFFFFFFF, but
needs to be able to return such a value, it may have no choice but to
perform 36-bit unsigned math in two 18-bit pieces.  Not impossible, but not
efficient either.

[toc] | [prev] | [next] | [standalone]


#97738

FromKeith Thompson <kst-u@mib.org>
Date2016-11-29 09:12 -0800
Message-ID<lnziki8b2b.fsf@kst-u.example.com>
In reply to#97735
supercat@casperkitty.com writes:
> On Tuesday, November 29, 2016 at 1:36:09 AM UTC-6, Keith Thompson wrote:
>> For example, int and unsigned int are both 36 bits.  The range of int is
>> shown as -2**35+1 to +2**35-1, and range of unsigned int as 0 to
>> 2**36-2.  (There's a conformance option that makes the upper bound of
>> unsigned int 2**36-1.)
>
> Hmm... I'd read of a machine whose conformance option lopped it to 2**35-1;
> I thought it was the same one, but it must have been a different one.
[...]

Ben posted a link:

https://public.support.unisys.com/aseries/docs/clearpath-mcp-16.0/pdf/86002268-205.pdf

(That's another indirect link; you'll need to open it in a browser and
click through the terms of use.)

It documents the C implementation for "ClearPath MCP 13.1".

(It makes the same nonsensical distinction between "int" and "signed
int", which are of course simply different names for the same type.)

int and unsigned int are both 48 bits (6 bytes).  int has a range of
-2**39+1 .. 2**39-1 (8 padding bits).  unsigned int has a range of
0 .. 2**39-1 (9 padding bits).

It's plausible that it uses the significand bits of the floating-point
format to store integers.  float and double are both 48 bits, with a
maximum value of 4.31359146674E68, which is just under 2**228, so the
format probably has 8 exponent bits, 1 sign bit, and 39 significand
bits.  (I don't know why the upper bound is 2**228 rather than 2**255 or
2**256.)

This system does use a sign-and-magnitude representation for integers,
and it does sacrifice the sign bit for unsigned types.  But it appears
to do so because it re-uses the floating-point representation, not
specifically because it's sign-and-magnitude.

-- 
Keith Thompson (The_Other_Keith) kst-u@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"

[toc] | [prev] | [next] | [standalone]


#97485

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-11-25 22:54 +0000
Message-ID<87shqf5fwd.fsf@bsb.me.uk>
In reply to#97475
Keith Thompson <kst-u@mib.org> writes:

> supercat@casperkitty.com writes:
>> On Friday, November 25, 2016 at 5:12:34 AM UTC-6, Ben Bacarisse wrote:
>>> It's not 100% clear if this is supposed to apply to unsigned int when
>>> int has the same positive range.  I'm not sure but I lean towards not.
>>> Why mention unsigned int if the objects in question were not supposed to
>>> exclude them?  Implementations where unsigned promotes to int would be
>>> pathological in some senses.
>>
>> Implementations where every unsigned value is representable as "int" are
>> hardly pathological.
>
> I won't argue the meaning of the word "pathological", but such
> implementations are certainly rare.

It was not a good word!  I'm not sure I meant anything other that "very
unusual".

>>                      That would actually be a common state of affairs in
>> sign-magnitude or ones'-complement implementations.
>
> I've never used a sign-and-magnitude or ones'-complement implementation,
> but I'd expect such an implementation to use all the bits of a word for
> both signed and unsigned types.  For example, if int and unsigned int
> are, say, 16 bits wide, I'd expect that most likely int would have a
> range of -32767..+32767, and unsigned int to have a range of 0..65535.
> Certainly there are other possibilities, including ones where the range
> of unsigned int matches the non-negative subrange of int, but I'd expect
> that to be unusual, perhaps even nonexistent.
>
> Do you have a concrete example, or are you just speculating?

Unisys systems are a good source because they have C compilers and odd
hardware.  I've found an example of both from that stable.  One[1] has
40-bit words where unsigned int has a padding bit and thus a range
exactly equal to that of signed int. (unsigned short and unsigned long
are also the same size for good measure.)  A wrinkle is that I don't
think this is a C99 compiler and the wording is different in C90.

The other[2] has 36-bit words and unsigned int uses all of them to give
the situation you describe.  This is, I think, a C99 compiler.

Do you have a view on whether the text in question is intended to
include unsigned being promoted to int?  Here it is in full:

  The following may be used in an expression wherever an int or unsigned
  int may be used:

  -- An object or expression with an integer type whose integer
     conversion rank is less than or equal to the rank of int and
     unsigned int.

  -- A bit-field of type _Bool, int, signed int, or unsigned int.

  If an int can represent all values of the original type, the value is
  converted to an int; otherwise, it is converted to an unsigned
  int. These are called the integer promotions.

I've always read the last paragraph more or less on it's own, but taken
together with the preceding text it seems at least possible that objects
or expressions of type unsigned int are not to be considered for
promotion, because the text is about those object of expression that can
be used instead of an int or unsigned int.

Maybe this is been resolved in a DR, but I could not find one in an
admittedly rather cursory search.

[1] MCP/AS, C Programming Reference Manual Volume 1: Basic
    Implementation, MCP 12.0, April 2008.

[2] Application Development Solutions, C Compiler Programming Reference
    Manual Volume 1: C Language and Library, Level 10R4, February 2013.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#97484

FromNick Bowler <nbowler@draconx.ca>
Date2016-11-25 22:01 +0000
Message-ID<o1acb3$545$2@dont-email.me>
In reply to#97455
On Fri, 25 Nov 2016 11:12:19 +0000, Ben Bacarisse wrote:
> [...]
>> On 25/11/16 09:44, Noob wrote:
>>> Integer promotion is applied to "an object or expression with an
>>> integer type whose integer conversion rank is less than or equal
>>> to the rank of int and unsigned int. If an int can represent all
>>> values of the original type, the value is converted to an int;
>>> otherwise, it is converted to an unsigned int."
> 
> It's not 100% clear if this is supposed to apply to unsigned int when
> int has the same positive range.

This was fixed in C11.  The text quoted above is changed, and now
reads (emphasis added):

  "An object or expression with an integer type (***other than int or
  unsigned int***) whose integer conversion rank is less than or equal
  to ..."

so it is clear that unsigned int never promotes to int.

[toc] | [prev] | [next] | [standalone]


#97487

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2016-11-25 23:22 +0000
Message-ID<87h96v5en0.fsf@bsb.me.uk>
In reply to#97484
Nick Bowler <nbowler@draconx.ca> writes:

> On Fri, 25 Nov 2016 11:12:19 +0000, Ben Bacarisse wrote:
>> [...]
>>> On 25/11/16 09:44, Noob wrote:
>>>> Integer promotion is applied to "an object or expression with an
>>>> integer type whose integer conversion rank is less than or equal
>>>> to the rank of int and unsigned int. If an int can represent all
>>>> values of the original type, the value is converted to an int;
>>>> otherwise, it is converted to an unsigned int."
>> 
>> It's not 100% clear if this is supposed to apply to unsigned int when
>> int has the same positive range.
>
> This was fixed in C11.  The text quoted above is changed, and now
> reads (emphasis added):
>
>   "An object or expression with an integer type (***other than int or
>   unsigned int***) whose integer conversion rank is less than or equal
>   to ..."
>
> so it is clear that unsigned int never promotes to int.

Ah, thanks.  I never thought to look at the later standard.  The
preamble lists "integer promotion rules" as one of the major changes so
one can't assume that this is just a clarification, but the
parenthetical phrase you highlighted is exactly the meaning I though was
a possible reading of the old wording.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#98697

FromTim Rentsch <txr@alumni.caltech.edu>
Date2016-12-10 07:22 -0800
Message-ID<kfn4m2blsg9.fsf@x-alumni2.alumni.caltech.edu>
In reply to#97487
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> Nick Bowler <nbowler@draconx.ca> writes:
>
>> On Fri, 25 Nov 2016 11:12:19 +0000, Ben Bacarisse wrote:
>>> [...]
>>>> On 25/11/16 09:44, Noob wrote:
>>>>> Integer promotion is applied to "an object or expression with an
>>>>> integer type whose integer conversion rank is less than or equal
>>>>> to the rank of int and unsigned int.  If an int can represent all
>>>>> values of the original type, the value is converted to an int;
>>>>> otherwise, it is converted to an unsigned int."
>>>
>>> It's not 100% clear if this is supposed to apply to unsigned int when
>>> int has the same positive range.
>>
>> This was fixed in C11.  The text quoted above is changed, and now
>> reads (emphasis added):
>>
>>   "An object or expression with an integer type (***other than int or
>>   unsigned int***) whose integer conversion rank is less than or equal
>>   to ..."
>>
>> so it is clear that unsigned int never promotes to int.
>
> Ah, thanks.  I never thought to look at the later standard.  The
> preamble lists "integer promotion rules" as one of the major changes so
> one can't assume that this is just a clarification, but the
> parenthetical phrase you highlighted is exactly the meaning I though was
> a possible reading of the old wording.

Most likely the earlier version was just an editorial oversight.
The "less than or equal to the rank of int and unsigned int" was
not present in C99, but added later in one of the TC's.

This suggests on extension of the internet spelling rule to
making editorial changes to the ISO standard.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web