Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #97397 > unrolled thread
| Started by | Francois Grieu <fgrieu@free.fr> |
|---|---|
| First post | 2016-11-24 15:33 +0100 |
| Last post | 2016-11-24 07:40 -0800 |
| Articles | 20 on this page of 27 — 9 participants |
Back to article view | Back to comp.lang.c
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 →
| From | Francois Grieu <fgrieu@free.fr> |
|---|---|
| Date | 2016-11-24 15:33 +0100 |
| Subject | Is 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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | Francois Grieu <fgrieu@free.fr> |
|---|---|
| Date | 2016-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]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-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]
| From | Noob <root@127.0.0.1> |
|---|---|
| Date | 2016-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]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-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]
| From | Nick Bowler <nbowler@draconx.ca> |
|---|---|
| Date | 2016-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]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | Nick Bowler <nbowler@draconx.ca> |
|---|---|
| Date | 2016-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-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]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2016-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