0

I need to use a 128 bit unsigned int variable in my code.
Searching on line I read about unsigned __int128. Here https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html I read

type __int128 is supported for targets which have an integer mode wide enough to hold 128 bits

My first question is what does it means with target? what I have to check to see if my pc can express such type?
The second question is how to print such kind of variable?
Lastly do I need to do something to use this kind of variables? The same above link says

Simply write __int128 for a signed 128-bit integer, or unsigned __int128 for an unsigned 128-bit integer.

So it seems I don't need to #include anything and I even don't add some option in gcc during the compiolation, is it right?

user1172131
  • 103
  • 7
  • 1
    "Target" is the target architecture, which you are writing your code for. Are you writing it for your PC only? – Eugene Sh. Feb 11 '21 at 19:07
  • 1
    There isn't support for printing built in to `printf` and friends, as far as I know. You have to write it yourself or find a third-party implementation. See https://stackoverflow.com/questions/25114597/how-to-print-int128-in-g – Nate Eldredge Feb 11 '21 at 19:11
  • Thank you for your answers; Eugene Sh so it means if my pc is a 32 bit or 64 bit machine, right? if this is the case has a 64 bit pc an integer mode wide enough to hold 128 bits? – user1172131 Feb 11 '21 at 19:17
  • @user1172131 no it has not. I think by target they understand the gcc code generator. None of the PC computers has 128-bit accumulator or registers (except vector ones but they do not count) – 0___________ Feb 11 '21 at 19:22
  • 1
    `gcc` [and `clang`] (e.g.) will generate code on a 32 bit system that allows `long long` [64 bit] to work using just 32 bit arithmetic. On a 64 bit machine, they use native 64 arithmetic (because the H/W supports it). Similarly, they generate code for 128 bit math using 64 bit instructions. It is built into the compiler. – Craig Estey Feb 11 '21 at 19:25
  • Craig Estey, so the point of the quote " is supported for targets which have an integer mode wide enough to hold 128 bits" is that the compiler can build 128 bit variable from 64 bit architecture but not from 32 bit ones, right? – user1172131 Feb 11 '21 at 19:30
  • Out of curiosity, can you say what you need it for? Are you trying to compute 25!, or something? :-) – Steve Summit Feb 11 '21 at 19:35
  • 1
    The compiler _could_ generate the necessary 32 bit instructions to do 128 bit math on a 32 bit H/W architecture. But, they _chose_ not to. To use 32 bit instructions -> 64 bit math or 64 bit insts -> 128 bit math, consider a multiply: For 32 -> 64, it takes 3 multiplies and two adds. About the same for 64 -> 128. So, 32 -> 128 might take 6 multiplies and 4 adds [or _worse_]. So, because of that they decided the code would be too cumbersome. Since most modern/typical systems have 64 bit in H/W, they decided to restrict the 128 bit impl to those systems. – Craig Estey Feb 11 '21 at 19:49
  • If you'd like _more_ precision than 128 bits, consider the `GMP` library: https://gmplib.org/ It is done in pure S/W. It is highly optimized and it adapts to whatever the native compiler can provide and will allow arbitrarily long numbers (e.g. 4096 bit numbers, if you wish). You have to use special/explicit GMP function calls (i.e. the compiler _can't_ generate it from `a * b`), so you'd have to plan for its use. – Craig Estey Feb 11 '21 at 20:00
  • Steve Summit In my code I generate random numbers with linear congruential generator (in particular my 64 bit generator has a multiplier ~2^62); Not entering in details, I want to parallelize the work executing more code simoultaneusly; to do so I have to be sure that the random numbers generated in each code is diffrent from the others (no overlap between the numbers generated in the codes). I use the linear congruential to derive from the first seed a second one sufficiently "distant". To do so I have to compute a^n where a is ~2^62 and n the distance (# of rand. numb. generated in 1 code ) – user1172131 Feb 11 '21 at 20:12
  • Given that you want this for an LCG, as you've described, just to ensure no dups. What do you want to parallelize? The LCG itself or what you do with the numbers? Maybe you should post a question about what you're trying to do in higher level terms. Assuming for any seed, your LCG has periodicity `p` of `2^n` where `n` is (e.g. 32, 64, ...). So, if you have `T` processes/tasks, a per-task seed value of `(p / T) * taskno` ??? – Craig Estey Feb 11 '21 at 21:27
  • Craig Estey I'm not sure I understand the last part of your comment. Anyway I want to parallelize what I do with the number; to do so I must be sure that I generate different random sequences in each executing code. I can't just take ,as seeds, numbers distant in absolute values cause they can potentially be near in the random sequence; starting to a certain seed I have to iterate the LCG relation a big number of times to be sure to be effectively distant from the starting seed. – user1172131 Feb 11 '21 at 21:49
  • With an LCG, it will be unique up to the period. So, if you have a large LCG [why I presume you wanted `__int128` to get a period of 2^127 or so], I _think_ you'd need to have _one_ LCG for _all_ threads. Either have a master task that sends out blocks of random numbers as messages (e.g. `msgsnd/msgrcv`). Or, you could wrap access to the LCG with a mutex (e.g. `lock(); rval = lcg(); unlock();`). Or, to reduce overhead, get a small run of numbers: `lock(); for (int idx = 0; idx < 10; ++idx) rval[idx] = lcg(); unlock();` where `rval` is in thread local storage. – Craig Estey Feb 12 '21 at 03:29
  • What I meant by the end of my earlier comment was, that if you have a separate [reentrant] seed for the LCG, and you start each thread's seed evenly spaced across the entire range, that's just a good as calling the LCG N times to "get some distance" [and a wee bit faster ;-)]. For example, if the LCG had period of 1,000,000 and you had five threads, using seeds of `1, 200000, 400000, 600000, 800000` is just about as good. Each thread will get 200,000 unique numbers. For a 128 bit LCG, the sub-period is much larger, so you'd likely never overlap in practice. – Craig Estey Feb 12 '21 at 03:36
  • Craig Estey I'm using a 64 bit LCG (MMIX (by Knuth)); my multiplier is ~2^62, so I easily move from low numbers to very high values inside my sequence. I don't understand why, starting each thread's seed evenly spaced across the entire range, assures me that those values are also distant inside the pseudo random sequence. In principle I should reach them in few steps even if they are very far in absolute value, isn't it?if you think I'm wrong please explain me why. I'm following your advice and create a new queston about it, – user1172131 Feb 12 '21 at 08:18
  • I've just created this question https://stackoverflow.com/questions/66168970/find-more-indipendent-seed-value-for-a-64-bit-lcg-mmix-by-knuth to better explain my main problem – user1172131 Feb 12 '21 at 09:36

1 Answers1

2
  1. "Target" means the specific combination of CPU architecture and operating system that your compiler is configured to create programs for. There is a discussion at Does a list of all known target triplets in use exist?. But "integer mode" is really a concept used internally by the compiler, and only indirectly related to what the hardware can and can't do. So all this really says is "the compiler supports 128-bit integers on some targets and not on others". The easiest way to find out whether yours does is to just try to compile and run a small test program that uses __int128.

  2. Most system's printf functions don't support __int128, so you have to write your own code to print them, or find third-party code somewhere. See How to print __int128 in g++? which is for C++ but still relevant.

  3. You don't need to include anything or use any special options.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82