home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c      Meh, in C you gotta define EVERYTHING      243,242 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 242,128 of 243,242   
   David Brown to Keith Thompson   
   Re: _BitInt(N)   
   25 Nov 25 07:56:30   
   
   From: david.brown@hesbynett.no   
      
   On 25/11/2025 02:23, Keith Thompson wrote:   
   > David Brown  writes:   
   >> On 24/11/2025 12:17, bart wrote:   
   >>> On 24/11/2025 09:29, David Brown wrote:   
   > [...]   
   >> 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.   
   >   
   > N + M, not N * M.   
      
   Of course.  (I /really/ should have picked a different third identifier...)   
      
   >   
   >> 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.   
   >   
   > Sort of.  C23 defines the term "generic function" (N3220 7.26.5.1,   
   > string search functions).  For example, strchr() can take a const void*   
   > argument and return a const void* result, or it can take a void*   
   > argument and return a void* result.  (C++ does this by having two   
   > overloaded strchr() functions.)   
   >   
   > These "generic functions" are (almost certainly) implemented as macros   
   > that use _Generic.  If you bypass the macro definition, you get the   
   > function that can take a const char* and return a char*.   
   >   
   > So C doesn't have type-generic functions, but it does have feature that   
   > let you implement things that act like type-generic functions.   
   >   
      
   Yes.  It has also had type-generic maths functions for a good while.   
   But it doesn't have a general generic function mechanism other than   
   _Generic macros.   
      
   >> 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.   
   >   
   > Indeed.  A _Generic selection that handles all the ordinary non-extended   
   > integer types needs to handle 12 cases if I'm counting correctly, which   
   > is feasible.  But the addition of bit-precise types adds   
   > BITINT_MAXWIDTH*2-1 new distinct predefined types, and a generic   
   > selection would need one case for each.   
   >   
   > However, you could have a function that takes a void*, a size, and a   
   > width as arguments and operates on a _BitInt(?) or unsigned _BitInt(?)   
   > type.  In fact, gcc has internal functions like that for multiplication   
   > and division.  (You mentioned something like that in text that I've   
   > snipped.)   
   >   
      
   You could, yes.  I started thinking about how you might make one that   
   didn't require the user to manually include the bitcount of the _BitInt   
   to use it, but I couldn't figure out a good way.  You can get a start,   
   from using sizeof on the _BitInt parameter, but I can't think of a way   
   to get bitcount exactly (even using _Generic's).   
      
   > [...]   
   >   
   >>> 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.)   
   >   
   > Yes, and in general a _BitInt argument has to be copied to the   
   > corresponding parameter, since a change to the parameter can't affect   
   > the value of the argument.   
      
   The workings of C parameter passing were unfortunately cut in stone   
   before anyone thought of passing large types as parameters.  In   
   hindsight it's easy to see it could have been better to say that   
   function parameters are implicitly "const" and attempting to modify them   
   is UB - just make a local copy if you want to make a change.  But it's   
   too late now!   
      
   >   
   > But passing huge _BitInts by value is no more problematic than passing   
   > huge structs by value.   
   >   
      
   Exactly, yes.   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca