From: antispam@fricas.org
David Brown wrote:
> On 24/11/2025 12:17, bart wrote:
>> On 24/11/2025 09:29, David Brown wrote:
>>> On 23/11/2025 16:06, Michael S wrote:
>>>> On Sun, 23 Nov 2025 13:59:59 +0000
>>>> bart wrote:
>>
>>>>> So what is the result type of multiplying values of those two types?
>>>>>
>>>>
>>>> I think, traditional C rules for integer types apply here as well: type
>>>> of result is the same as type of wider operand. It is arithmetically
>>>> unsatisfactory, but consistent with the rest of language.
>>>
>>> There is one key difference between the _BitInt() types and other
>>> integer types - with _BitInt(), there are no automatic promotions to
>>> other integer types. Thus if you are using _BitInt() operands in an
>>> arithmetic expression, these are not promoted to "int" or "unsigned
>>> int" even if they are smaller (lower rank). If you mix _BitInt()'s of
>>> different sizes, then the smaller one is first converted to the larger
>>> type.
>>
>>>> I think, the Standard is written in such way that implementing _BitInt
>>>> as an arbitrary precision numbers, i.e. with number of bits held as part
>>>> of the data, is not allowed.
>>
>>> Correct. _BitInt(N) is a signed integer type with precisely N value
>>> bits. It can have padding bits if necessary (according to the target
>>> ABI), but it can't have any other information.
>>>
>>>> Of course, Language Support Library can be
>>>> (and hopefully is, at least for gcc; clang is messy a.t.m.) based on
>>>> arbitrary precision core routines, but the API used by compiler should
>>>> be similar to GMP's mpn_xxx family of functions rather than GMP's
>>>> mpz_xxx family, i.e. # of bits as separate parameters from data arrays
>>>> rather than combined.
>>>>
>>>
>>> Yes, exactly. At the call site, the size of the _BitInt type is
>>> always a known compile-time constant, so it can easily be passed on.
>>> Thus :
>>>
>>> _BitInt(N) x;
>>> _BitInt(M) y;
>>> _BitInt(NM) z = x * y;
>>
>> So what is NM here; is it N*M (the potential maximum size of the
>> result), or max(N, M)?
>
> No, it is whatever you want it to be. I didn't want to use the next
> letter after N because _BitInt(O) could easily be misunderstood. But of
> course NM could be misunderstood too. Perhaps N1, N2 and N3 would have
> been better choices than N, M and NM.
>
> You pick the size of "z" here according to your needs for your code.
> The multiplication will be done, logically, at max(N, M) bits. The
> result will then be converted to NM bits. Like always in C, the
> semantics of the calculation is entirely independent of the type of the
> variable you assign the results to. And like always in C, the compiler
> may take advantage of knowledge of the assigned type in order to give
> more efficient code, as long as it does not stray from giving the same
> value as if it took the code literally.
>
> So if you want the full range of values of x and y to be usable here,
> then NM would have to be N * M. But you would also need a cast, such as
> "_BitInt(NM) z = (_BitInt(NM)) x * y;", just as you do if you want to
> multiply two 32-bit ints as a 64-bit operation.
>
> Alternatively, you might know more about the values that might be in x
> and y, and have a smaller NM (though you still need a cast if it is
> greater than both N and M). Or you might be using unsigned types and
> want the wrapping / masking behaviour.
>
> The point was not what size NM is, but that it is known to the compiler
> at the time of writing the expression.
>
>>
>> It sounds like the max precision you get will be the latter.
>>
>>
>>> can be implemented as something like :
>>>
>>> __bit_int_signed_mult(NM, (unsigned char *) &z,
>>> N, (const unsigned char *) &x,
>>> M, (const unsigned char *) &y);
>>>
>>>
>>
>>
>> How would you write a generic user function that operates on any size
>> BitInt? For example:
>>
>> _BitInt(?) bi_square(_BitInt(?));
>>
>
> You can't. _BitInt(N) and _BitInt(M) are distinct types, for differing
> N and M. You can't write a generic user function in C that implements
> "T foo(T)" where T can be "int", "short", "long int", or other types. C
> simply does not have type-generic functions.
>
> You /can/ write generic macros that handle different _BitInt types, but
> that would quickly get painful given that you'd need a case for each
> size of _BitInt you wanted for the _Generic macro.
>
> If you want generics, you are better off with a language that supports
> generics, such as C++.
>
>> Even if you passed the size as a parameter, there would be a problem
>> with the BitInt type.
>
> Yes. But you could use a void* pointer for more generic parameters.
>
> However, _BitInt types are for "bit-precise integer types". They are
> for specific fixed sizes, not for arbitrary precision integers. They
> are not ideally suited for tasks for which they were not designed -
> that's hardly surprising.
>
>>
>> This assumes BitInts are passed and returned by value, but even using
>> BitInt* wouldn't help.
>
> Yes, they are passed around as values - they are integer types and are
> passed around like other integer types. (Implementations may use stack
> blocks and pointers for passing the values around if they are too big
> for registers, just as implementations can do with any value type.
> That's an implementation detail - logically, they are passed and
> returned as values.)
>
>>
>> This sets it apart from arrays, where you also define very large, fixed
>> size arrays, but can use a T(*)[] type to write generic functions, that
>> take an additional length parameter.
>
> _BitInt's are fixed-size integer types, not arrays. Again, it is not
> then surprising that they are different from arrays.
>
>>
>> This will be for a particular T, but for BitInt, T is also fixed; it
>> happens to be an implicit bit type.
>>
>
> _BitInt's are not arrays, they are scalars - they are integer types.
> There is no concept of a type "_BitInt" - they always have compile-time
> fixed sizes, such as "_BitInt(12)". So the idea of passing around
> generic _BitInt's makes no more sense than passing around any other kind
> of generic integer types. (Of course you can have an array of _BitInt's
> of any given size.)
There are languages which pass generic types, but C is not one
of them. So idea of passing around generic _BitInt's makes sense,
but this is not included in C.
--
Waldek Hebisch
--- SoupGate-Win32 v1.05
* Origin: you cannot sedate... all the things you hate (1:229/2)
|