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,152 of 243,242   
   David Brown to bart   
   Re: _BitInt(N) (1/2)   
   26 Nov 25 08:55:37   
   
   From: david.brown@hesbynett.no   
      
   On 25/11/2025 22:58, bart wrote:   
   > On 25/11/2025 20:25, David Brown wrote:   
   >> On 24/11/2025 23:27, bart wrote:   
   >   
   >>> On interesting use-case for literals was short-strings; 128 bits   
   >>> allowed character literals up to 16 characters: 'ABCDEFGHIJKLMNOP'. I   
   >>> think C is still stuck at one, or 4 if you're lucky.)   
   >>>   
   >>   
   >> I have no idea or opinion on why /you/ might want 128-bit or larger   
   >> integer types.  I believe there is very little use for "normal"   
   >> numbers - things you might want to write as literals, calculate with,   
   >> and read or write - that won't fit perfectly well within 64 bit types,   
   >> and would not be better served by arbitrary sized integers.   
   >   
   >   
   >>   Arbitrary sized integers are a very different kettle of fish from   
   >> large fixed-size integers, and are not something that would fit in the   
   >> C language - they need a library.   
   >   
   > Really? I wouldn't have thought there was any appreciable difference   
   > between the code for multiplying two 100,000-bit BitInts, and that for   
   > multiplying two abitrary-precision ints that happen to be 100,000 bits.   
   >   
      
   You are looking at things in completely the wrong way.   
      
   Long before you start thinking of how to implement operations, think   
   about what the types are at a fundamental level.   
      
   A fixed-size integer is a value type of fixed, compile-time size.  It is   
   passed around as a value.  Local instances can be put on a stack with   
   compile-time fixed offsets (and thus using [sp + N] access modes in an   
   implementation).  The type has a single simple and obvious (albeit   
   slightly implementation-dependent) bit representation.  A _BitInt(32)   
   will be identical at the low level to an int32_t.  Bigger _BitInt types   
   are just the same, only bigger.  There is no difference in concept, or   
   representation, whether the type is 32-bit or 32 million bits.   
      
   An arbitrary sized integer is a dynamic type with variable size.  The   
   base object will hold information about pointers to data, sizes for that   
   stored data - including both how much is in use, and how much is   
   available.  There are endless ways to make such types - you can support   
   multiple allocation parts, or use a single contiguous allocation.  You   
   can store the data in binary, or some kind of packed decimal, or other   
   formats.  Passing them around might mean just passing around the base   
   object, but sometimes you need to make deep copies.  Operations might   
   lead to heap memory allocations or deallocations.   
      
   They are so /totally/ different that any similarities in the way you do   
   a particular arithmetic operation are completely incidental.   
      
      
   > Maybe the latter is autoranging, and might give a 200,000-bit result.   
   >   
   > Presumably the former doesn't use inline code, so it would be surprising   
   > if each distinct size of BitInt had dedicated sets of routines for this.   
   > So it sounds like they have to use a generic library anyway.   
   >   
   > And sure enough, gcc-generated code contains stuff like this:   
   >   
   >      mov    r8, rcx   
   >      mov    edx, 50000       # (BitInt(50000)   
   >      mov    rcx, rax   
   >      call    __mulbitint3   
   >   
   > So, BitInts are different in that they /don't/ need a library?   
   >   
   >>   
   >> I can tell you why /I/ might find larger integer types useful.  They   
   >> include :   
   >>   
   >> * 128-bit for IPv6 address.  These use a variety of styles for input   
   >> and display, and thus would use specialised routines, not simple   
   >> literals or printf-style IO.   
   >   
   > So, a better fit for a struct then? Here I'm curious as to what   
   > BitInt(128) brings to the table.   
   >   
      
   A struct is certainly what I use today.  But there may be times when it   
   is convenient to hold the data in a single scalar object.  Depending on   
   the target device, registers, and operations, there might be registers   
   that can hold a 128-bit scalar for passing it around, or for atomically   
   accessing them.   
      
   >   
   >> * Big units for passing data around with larger memory transfers,   
   >> using SIMD registers.  IO is irrelevant here.   
   >   
   > Structs and arrays again spring to mind if you just want an anonymous   
   > data block. (I wonder why it has to be bit-precise for byte-addressed   
   > memory?)   
   >   
      
   If I have a processor that has 256-bit vector registers, then moving   
   data by loading and storing 256-bit blocks is going to be more efficient   
   than doing a loop of 16 byte moves.  Today, I would use uint64_t for the   
   task, as the biggest type available.  Why does it have to be   
   bit-precise?  It must be bit-precise because I would want to move 256   
   bits - not 255 bits or 257 bits.   
      
   >   
   >> * Cryptography.  IO is irrelevant here.  But a variety of sizes are   
   >> useful including 56, 80, 112, 128, 168, 192, 384, 512, 521, 2048,   
   >> 3072, 4096, 7680, 8096 bits.  There may be more common sizes - I'm   
   >> just thinking of DES, 3DES, AES, SHA, ECC and RSA.   
   >   
   > And I'm again curious as to what /non-numeric/ use a 200,000-bit BitInt   
   > might be put to, that is not better served by an array or struct.   
   >   
      
   I don't have a use for a 200,000 bit integer type at the moment.  But I   
   cannot imagine any reason why the language specifications should have   
   arbitrary limits.  Are you suggesting that the C standards show say "You   
   can have _BitInt's up to 8096 because someone found a use for them, but   
   you can't have size 8097 and above - and 200,000 is right out - because   
   someone else can't imagine they are useful" ?   
      
   An implementation can - indeed, must - set a limit to the sizes it   
   supports.  Implementations can have many reasons to do so.  Some   
   implementations might have quite low limits (the size of "long long int"   
   is the minimum allowed for conformance), but then that implementation   
   might not be so useful to some people.   
      
   > Maybe bit-sets? But there are no special features for accessing   
   > individual bits.   
   >   
   > That BigInt() defaults to a signed integer (twos complement?), even for   
   > very large sizes suggests that /numeric/ applications are a primary use.   
   >   
      
   Obviously the C standards should have made "_BitInt" signed up to size   
   73 bits, and unsigned from then on.  That would have been /so/ much   
   clearer and simpler for everyone.   
      
   >>   
   >>   
   >> Smaller sizes can be useful for holding RGB pixel values, audio data,   
   >> etc.   
   >   
   > Except that these are probably rounded up, to the next multiple of two.   
   > So the benefit is minimal; it do something with those padding bits.   
   >   
      
   I write C code.  I want my C code to be clear and represent what I am   
   handling, and then let the compiler do its job of generating efficient   
   results.  So if I am dealing with data that is 24-bit signed integer   
   data, then _BitInt(24) (especially with a typedef name) is more accurate   
   source code than "int" or "int32_t".   
      
      
   [continued in next message]   
      
   --- 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