I'm doing a Codewars Challenge. I must square every digit of a number and concatenate them.
So, if we run 9119 through the function, 811181 will come out, because 92 is 81 and 12 is 1.
My code is below:
#include <math.h>
unsigned long long square_digits (unsigned n)
{
// Count for digits
int digits = log10(n) + 1, i = 0;
// Array to store the split number
int numDivided[digits];
// Store concatenated numbers
unsigned long long result = 0;
if (n == 0)
{
return result;
}
// Split number and store their square
while (n > 0)
{
numDivided[i] = pow(n % 10, 2);
n /= 10;
i++;
}
// Concatenated square of numbers
for (i = digits - 1;i >= 0;i--)
{
if (numDivided[i] == 0)
{
result *= 10;
}
else
{
// Count digits of the current number
digits = log10(numDivided[i]) + 1;
// Multiply current result for 10^(digits)
result *= pow(10, digits);
// Add the current number to result
result += numDivided[i];
}
}
return result;
}
The test cases are below:
Test(test_suite, sample_tests)
{
do_test( 3212u, 9414ull);
do_test( 2112u, 4114ull);
do_test( 0u, 0ull);
do_test( 999u, 818181ull);
do_test( 10001u, 10001ull);
do_test(3210987654u, 9410816449362516ull);
do_test(3999999999u, 9818181818181818181ull); // :p
do_test( UINT_MAX, 164811681364948125ull);
}
The code works until the two last tests, so:
for n = 3999999999, expected 9818181818181818181, but got 9818181818181818449
I was think that the test case was wrong and check if the number was greater that ULLONG_MAX but it's less, so, all right.
What is my mistake at this point?
What problems could i have with pow function? There is any alternative?
pow() typically returns, at best, a 53 significant bit result yet we have at least a 64-bit problem. powl() does not certianly help either as it may be as limiting as pow(). Do not use floating point functions for an integer problem. Using a floating point funtion for an integer problem is the wrong approach.
digits = log10(n) + 1 are numDivided[i] = pow(n % 10, 2) are not specified to get the desired value (due to imprecision) and certainly fail when n == 0.
Simple extract the least significant decimal digit with %10. Scale by an integer type power-of-10.
unsigned long long square_digits(unsigned n) {
unsigned long long nn = 0;
unsigned long long pow10 = 1;
while (n) {
unsigned digit = n % 10;
unsigned square = digit * digit; // 0 to 81
nn += square * pow10;
if (square < 10) {
pow10 *= 10;
} else {
pow10 *= 100;
}
n /= 10;
}
return nn;
}
The main culprit is this line:
result *= pow(10, digits);
Given that result is an unsigned long long while the return value of pow is a double, result is first converted to a double, then multiplied by the power and finally the result is converted back to an unsigned long long.
The problem is that while a double type has a much greater range than an unsigned long long, its precision is limited and not all the possible integral values can be represented (stored) exactly.
In particular, you can check the result of the following line:
printf("%.0lf\n", 981818181818181ull * 100.0); // It won't print 98181818181818100
See #chux's answer for further details and a proper implementation of the solution.
I found two mistakes in your code.
log() is not defined for 0. So, you cannot run your code against Test case 3.
Use powl() instead of pow().
PS: One change you can do to pass test case 3 is check if N == 0 in the beginning of the function itself. The next script should calculate the number of digits in N.
Related
I'm trying to code a program that can tell apart real and fake credit card numbers using Luhn's algorithm in C, which is
Multiply every other digit by 2, starting with the number’s
second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total
modulo 10 is congruent to 0), the number is valid!
Then I coded something like this (I already declared all the functions at the top and included all the necessary libraries)
//Luhn's Algorithm
int luhn(long z)
{
int c;
return c = (sumall(z)-sumodd(z)) * 2 + sumaodd(z);
}
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
But somehow it always gives out the wrong answer even though there's no error or bug detected. I came to notice that it works fine when my variable z stands alone, but when it's used multiple times in the same line of code with different functions, their values get messed up (in function luhn). I'm writing this to ask for any fix I can make to make my code run correctly as I intended.
I'd appreciate any help as I'm very new to this, and I'm not a native English speaker so I may have messed up some technical terms, but I hope you'd be able to understand my concerns.
sumall is wrong.
It should be sumeven from:
Add the sum to the sum of the digits that weren’t multiplied by 2.
Your sumall is summing all digits instead of the non-odd (i.e. even) digits.
You should do the * 2 inside sumodd as it should not be applied to the other [even] sum. And, it should be applied to the individual digits [vs the total sum].
Let's start with a proper definition from https://en.wikipedia.org/wiki/Luhn_algorithm
The check digit is computed as follows:
If the number already contains the check digit, drop that digit to form the "payload." The check digit is most often the last digit.
With the payload, start from the rightmost digit. Moving left, double the value of every second digit (including the rightmost digit).
Sum the digits of the resulting value in each position (using the original value where a digit did not get doubled in the previous step).
The check digit is calculated by 10 − ( s mod 10 )
Note that if we have a credit card of 9x where x is the check digit, then the payload is 9.
The correct [odd] sum for that digit is: 9 * 2 --> 18 --> 1 + 8 --> 9
But, sumodd(9x) * 2 --> 9 * 2 --> 18
Here's what I came up with:
// digsum -- calculate sum of digits
static inline int
digsum(int digcur)
{
int sum = 0;
for (; digcur != 0; digcur /= 10)
sum += digcur % 10;
return sum;
}
// luhn -- luhn's algorithm using digits array
int
luhn(long z)
{
char digits[16] = { 0 };
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
// split into digits (we use little-endian)
int digcnt = 0;
for (digcnt = 0; z != 0; ++digcnt, z /= 10)
digits[digcnt] = z % 10;
int sum = 0;
for (int digidx = 0; digidx < digcnt; ++digidx) {
int digcur = digits[digidx];
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
// luhn -- luhn's algorithm using long directly
int
luhn2(long z)
{
// get check digit and remove from "payload"
int check_expected = z % 10;
z /= 10;
int sum = 0;
for (int digidx = 0; z != 0; ++digidx, z /= 10) {
int digcur = z % 10;
if ((digidx & 1) == 0)
sum += digsum(digcur * 2);
else
sum += digcur;
}
int check_actual = 10 - (sum % 10);
return (check_actual == check_expected);
}
You've invoked undefined behavior by not initializing a few local variables in your functions, for instance you can remove your undefined behaviour in sumodd() by initializing a to zero like so:
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a = 0; //Initialize
while(x)
{
a += x % 10; //You can "a += b" instead of "a = a + b"
x /= 100;
}
return a;
}
It's also important to note that long is only required to be a minimum of 4-bytes wide, so it is not guaranteed to be wide enough to represent a decimal-16-digit-integer. Using long long solves this problem.
Alternatively you may find this problem much easier to solve by treating your credit card number as a char[] instead of an integer type altogether, for instance if we assume a 16-digit credit card number:
int luhn(long long z){
char number[16]; //Convert CC number to array of digits and store them here
for(int c = 0; c < 16; ++c){
number[c] = z % 10; //Last digit is at number[0], first digit is at number[15]
z /= 10;
}
int sum = 0;
for(int c = 0; c < 16; c += 2){
sum += number[c] + number[c + 1] * 2; //Sum the even digits and the doubled odd digits
}
return sum;
}
...and you could skip the long long to char[] translation part altogether if you treat the credit card number as an array of digits in the whole program
This expression:
(sumall(z)-sumodd(z)) * 2 + sumall(z);
Should be:
((sumall(z)-sumodd(z)) * 2 + sumodd(z))%10;
Based on your own definition.
But how about:
(sumall(z) * 2 - sumodd(z))%10
If you're trying to be smart and base off sumall(). You don't need to call anything twice.
Also you don't initialise your local variables. You must assign variables values before using them in C.
Also you don't need the local variable c in the luhn() function. It's harmless but unnecessary.
As others mention in a real-world application we can't recommend enough that such 'codes' are held in a character array. The amount of grief caused by people using integer types to represent digit sequence 'codes' and identifiers is vast. Unless a variable represents a numerical quantity of something, don't represent it as an arithmetic type. More issue has been caused in my career by that error than people trying to use double to represent monetary amounts.
#include <stdio.h>
//sum of digits in odd position starting from the end
int sumodd(long x)
{
int a=0;
while(x)
{
a = a + x % 10;
x /= 100;
}
return a;
}
//sum of all digits
int sumall(long y)
{
int b=0;
while(y)
{
b = b + y % 10;
y /= 10;
}
return b;
}
//Luhn's Algorithm
int luhn(long z)
{
return (sumall(z)*2-sumodd(z))%10;
}
int check_luhn(long y,int expect){
int result=luhn(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumodd(long y,int expect){
int result=sumodd(y);
if(result==expect){
return 0;
}
return 1;
}
int check_sumall(long y,int expect){
int result=sumall(y);
if(result==expect){
return 0;
}
return 1;
}
int main(void) {
int errors=0;
errors+=check_sumall(1,1);
errors+=check_sumall(12,3);
errors+=check_sumall(123456789L,45);
errors+=check_sumall(4273391,4+2+7+3+3+9+1);
errors+=check_sumodd(1,1);
errors+=check_sumodd(91,1);
errors+=check_sumodd(791,8);
errors+=check_sumodd(1213191,1+1+1+1);
errors+=check_sumodd(4273391,15);
errors+=check_luhn(1234567890,((9+7+5+3+1)*2+(0+8+6+4+2))%10);
errors+=check_luhn(9264567897,((9+7+5+6+9)*2+(7+8+6+4+2))%10);
if(errors!=0){
printf("*ERRORS*\n");
}else{
printf("Success\n");
}
return 0;
}
I've been working on a code that converts a given number (decimal base) to any other base from 2 to 16.
Clearly, I've come across the issue that the function base_conversion_it (it stands for iterative) prints the values in reverse.
I cannot use arrays nor pointers, and everyone on the internet seems to solve this issue like that. My assignment requires making both an iterative and a recursive function (which I did and works).
void base_conversion_it(unsigned int n, unsigned int b) {
if (n > 0) {
//bases between 2 and 16
if (b >= 2 && b <= 16) {
int r; //r = remainder
int q = 1; //quotient
int num; //saves the remainder
while (q != 0) {
r = n % b;
printf("%X", r);
q = n / b;
n = q;
}
}
}
}
You start converting from the units digit.
Maybe start with the most significant digit instead?
// It's Undefined Behaviour if `b` is outside the range [2...16]
void base_conversion_it(unsigned int n, unsigned int b) {
unsigned highestbase = 1;
while (highestbase * b <= n) highestbase *= b; //possible wrap around and infinite loop
while (highestbase) {
printf("%X", n / highestbase);
n %= highestbase;
highestbase /= b;
}
printf("\n");
}
Sorry missed iterative.
char digits[] = "0123456789ABCDEFGHIJKLMNOP";
void print(unsigned long long val, unsigned base)
{
unsigned long long mask = base;
while(val / mask >= base) mask *= base;
do
{
printf("%c", digits[val / mask]);
val %= mask;
mask /= base;
}while(val);
}
int main(void)
{
print(45654756453, 10); printf("\n");
print(45654756453, 16); printf("\n");
print(45654756453, 24); printf("\n");
print(45654756453, 2); printf("\n");
}
https://godbolt.org/z/W3fGnnhYs
Recursion:
char digits[] = "0123456789ABCDEF";
void print(unsigned long long val, unsigned base)
{
if(base <= 16 && base > 1)
{
if(val >= base) print(val / base, base);
printf("%c", digits[val % base]);
}
}
https://godbolt.org/z/84hYocnjv
If you cannot use either arrays (including strings) or recursion, then I think you need to compute the output digits in most-significant-first order. This is a bit less natural than computing them in the opposite order and reversing the result, but it can be done:
use a loop to find the place value of the most significant non-zero base-b digit of n. For example, check the result of dividing n by successive powers of b until the result is 0, then back off one step.
In a separate loop, read off the base-b digits of n one by one, starting with the one at the discovered most-significant position. For each digit,
Divide the current value of n by the place value pv of the current digit to get a digit value.
Replace n with n % pv.
Be careful to continue all the way down to place value 1, as opposed, say, to stopping when n becomes zero.
This is the function to calculate the factorial of very large numbers. This works perfectly fine but the time complexity is quite high. How to reduce time complexity?
This function is called once.
Current time to find factorial 0f 1 million is 40 000ms;
Expected time: 10 000ms
static void calcfactorial(unsigned int n)
{
unsigned int carry, i, j;
len = factorial[0] = 1;
for (i = 1; i < LEN; i++)
factorial[i] = 0;
for (i = 2; i <= n; i++)
{
carry = 0;
for (j = 0; j < len; j++)
{
factorial[j] = factorial[j] * i + carry;
carry = factorial[j] / 10;
factorial[j] = factorial[j] % 10;
}
while (carry)
{
factorial[len++] = carry % 10;
carry = carry / 10;
}
}
}
Since you only need a four-fold improvement in time, the following may suffice:
Use a wider (unsigned) integer type, such as uint64_t.
Instead of calculating in base ten, use the largest power of ten, B, such that B•N fits in the integer type1, where N is the number you are computing the factorial of. For example, for 64-bit integers and 1,000,000!, you could use base 1013.
When doing multiplications, do not multiply by every digit in the product array, as the loop for (j = 0; j < len; j++) does. All digits beyond the first start as zero, and they slowly become non-zero as work progresses. Track the highest non-zero digit, and do multiplications only up to that digit, until the product carries into the next digit.
Similarly, the low digits become zero as the work progresses, due to accumulating factors of the base in the factorial. Track the lowest non-zero digit, and start work there.
A program demonstrating these is below.
A significant cost in this program is the divisions by the base. If you switch to a power-of-two base, these become bitwise operations (shifts for division and bitwise AND operations for remainders), which are much cheaper. This should speed up computing the factorial considerably. However, the final product will have to be converted to decimal for output. That will have a lower cost than computing entirely in decimal, so it is a win.
After that, you might consider this answer in Computer Science Stack Exchange. It suggests restructuring the factorial as powers of primes and using repeated squaring to compute the powers of primes, which are then multiplied.
This answer suggests using n! ≈ sqrt(2πn)•(n/e)n, which would require more sophisticated mathematics and programming.
Footnote
1 The purpose of using a power of ten is then the result can be directly printed from its base-B digits.
Demonstration
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* Define T to be an unsigned integer type. The larger the better up to the
widest type supported efficiently (generally the widest type for which the
processor has arithmetic instructions).
Define PRIuT to be a printf conversion specifier to print a type T as an
unsigned decimal numeral.
*/
typedef uint64_t T;
#define PRIuT PRIu64
// Return the base-10 logarithm of x, rounded down.
static unsigned ilog10(T x)
{
unsigned log = 0;
for (; 10 <= x; x /= 10)
++log;
return log;
}
// Return 10**x.
static T iexp10(unsigned x)
{
T power = 1;
for (; 0 < x; --x)
power *= 10;
return power;
}
int main(void)
{
// Set the value we want the factorial of.
static const T N = 1000000;
// Set the maximum value of T by using wrapping.
static const T MaximumT = -1;
/* Determine the maximum number of decimal digits we can use easily:
Given a number with Digits decimal digits, Digits*N will be
representable in a T.
*/
unsigned Digits = ilog10(MaximumT/N);
/* Set Base to 10**Digits. This is the numerical base we will do
arithmetic in -- like base ten, but more efficient if it is bigger.
*/
T Base = iexp10(Digits);
/* Set an array size that is sufficient to contain N!
For 1 < N, N! < N**N, so the number of digits in N! is less than
log10(N**N) = N * log(10). Since we are using ilog10, which rounds
down, we add 1 to it to round up, ensuring we have enough room.
Then we divide that number of digits by the number of digits we will
have in each array element (and round up, by subtracting one before the
division and adding one after), and that is the number of array
elements we allocate.
*/
size_t S = (N * (ilog10(N)+1) - 1) / Digits + 1;
T *Product = malloc(S * sizeof *Product);
if (!Product)
{
fprintf(stderr,
"Error, unable to allocate %zu bytes.\n", S * sizeof *Product);
exit(EXIT_FAILURE);
}
/* Initialize the array to 1. L and H remember the index of the lowest
and highest non-zero array element, respectively. Since all the
elements before L or after H are zero, we do not need to use them in
the multiplication.
*/
Product[0] = 1;
size_t L = 0, H = 0;
// Multiply the product by the numbers from 2 to N.
for (T i = 2; i <= N; ++i)
{
// Start with no carry.
T carry = 0;
/* Multiply each significant base-Base digit by i, add the carry in,
and separate the carry out. We start separately with the lowest
non-zero element so we can track if it becomes zero.
*/
while (1)
{
T t = Product[L] * i + carry;
carry = t / Base;
if ((Product[L] = t % Base)) // Leave when digit is non-zero.
break;
++L; // If digit is zero, increase L.
}
for (size_t j = L+1; j <= H; ++j)
{
T t = Product[j] * i + carry;
carry = t / Base;
Product[j] = t % Base;
}
// If there is a final carry out, put it in a new significant digit.
if (0 != carry)
Product[++H] = carry;
}
/* Print the result. The first base-Base digit is printed with no
leading zeros. All subsequent base-Base digits are printed with
leading zeros as needed to ensure exactly Digit decimal digits are
printed.
*/
printf("%" PRIuT, Product[H]);
for (size_t j = H; 0 < j--;)
printf("%0*" PRIuT, Digits, Product[j]);
printf("\n");
free(Product);
}
So i'm supposed to find out the last 10 digits of 2^n(0<=n<=100) where n is the input. I found a method to handle large numbers but the program fails when n>64. Any leads on how to go about with this would be appreciated.
#include<stdio.h>
#include<math.h>
/* Iterative Function to calculate (x^y)%p in O(log y) */
int power(long long int x, long long int y, long long int p)
{
long long int res = 1; // Initialize result
x = x % p; // Update x if it is more than or
// equal to p
while (y > 0) {
// If y is odd, multiply x with result
if (y & 1)
res = (res * x) % p;
// y must be even now
y = y >> 1; // y = y/2
x = (x * x) % p;
}
return res;
}
// C function to print last 10 digits of a^b
void printLastDigits(long long int a,long long int b)
{
long long int temp = pow(10,10);
// Calling modular exponentiation
temp = power(a, b, temp);
if (temp)
printf("%d",temp);
}
int main()
{
long long int n;
scanf("%d",&n);
printLastDigits(2,n);
return 0;
}
You don't need to worry about the 'high' bits, since multiplication by 2 left shifts them out of range of the lower part of the product you're interesting in. Just be sure you're using the unsigned long long type (of at least 64 bits) to hold integral types that are wide enough, e.g.,
#include <inttypes.h>
#include <stdio.h>
void low_digits (unsigned int n)
{
unsigned long long base = 2, modulus = 10000000000ULL;
for (unsigned int i = 1; i <= n; i++)
{
fprintf(stdout, "2^%u mod 10^10 = %llu\n", i, base);
base = (base * 2) % modulus;
}
}
You can test 2^1000 with a bignum calculator:
10715086071862673209484250490600018105614048117055336074437503883703\
51051124936122493198378815695858127594672917553146825187145285692314\
04359845775746985748039345677748242309854210746050623711418779541821\
53046474983581941267398767559165543946077062914571196477686542167660\
429831652624386837205668069376
while n = 1000 above yields: 5668069376
Others have noted, that this is a naive method, and modular exponentiation is far more efficient for sufficiently large values of (n). Unfortunately, this is going to require products that exceed the range of an unsigned 64-bit value, so unless you're prepared to implement [hi64][lo64] multi-precision mul / mod operations, it's probably beyond the scope of your task.
Fortunately, later versions of gcc and clang do provide an extended 128 bit integral type:
#include <inttypes.h>
#include <stdio.h>
void low_digits (unsigned int n)
{
unsigned long long base = 2, modulus = 10000000000ULL;
__extension__ unsigned __int128 u = 1, w = base;
while (n != 0)
{
if ((n & 0x1) != 0)
u = (u * w) % modulus; /* (mul-reduce) */
if ((n >>= 1) != 0)
w = (w * w) % modulus; /* (sqr-reduce) */
}
base = (unsigned long long) u;
fprintf(stdout, "2^%u mod 10^10 = %llu\n", n, base);
}
The following uses strings to perform the multiplication:
void lastdigits(char digits[11], int n)
{
int i, j, x, carry;
for (i=0; i<n;i++) {
for (j=9, carry=0; j>=0; j--) {
x= digits[j]-'0';
x *= 2;
x += carry;
if (x>9) {carry= 1; x -= 10;}
else carry= 0;
digits[j]= x+'0';
}
}
}
void test(void)
{
char digits[11];
strcpy(digits,"0000000001");
lastdigits(digits,10);
printf("%s\n",digits);
strcpy(digits,"0000000001");
lastdigits(digits,20);
printf("%s\n",digits);
strcpy(digits,"0000000001");
lastdigits(digits,100);
printf("%s\n",digits);
}
Output:
0000001024
0001048576
6703205376
Since the other answers you've received don't actually show what you're doing wrong:
x = (x * x) % p;
You're assuming that x * x still fits in long long int. But if x is 0x100000000 (4294967296, for 10 decimal digits) and long long int is 64 bits, then it will not fit.
Either:
You need a way to accurately multiply two arbitrary 10-digit numbers. The result may have 20 digits and may not fit in long long int or even unsigned long long int. This means you'd need to use some bigint library or implement something like that yourself.
Or:
You need to avoid multiplying multiple possibly-10-digit numbers.
The answer you've accepted opts for simple repeated multiplication by 2. This is sufficient for your problem now, but beware that this does significantly increase the complexity if you want to allow very large exponents.
Let's say you are finding the last digit of 2^n, you just need to consider last digit and ignore every other digit
1. 2*2 = 4
2. 4*2 = 8
3. 8*2 = 16 (ignore last-but-one digit i.e 1)
4. 6*2 = 12 (ignore last-but-one digit i.e 1)
5. 2*2 = 4
6. 4*2 = 8
7. 8*2 = 16 (ignore last-but-one digit i.e 1)
8. 6*2 = 12 (ignore last-but-one digit i.e 1)
9. 2*2 = 4
... n-1 iterations
To find the last 2 digits of 2^n, ignore all digits except last 2 digits.
1. 2*2 = 4
2. 4*2 = 8
3. 8*2 = 16
4. 16*2 = 32
5. 32*2 = 64
6. 64*2 = 128 (Consider last 2 digits)
7. 28*2 = 56
8. 56*2 = 112 (Consider last 2 digits)
9. 12*2 = 24
... n-1 iterations
Similarly, to find the last 10 digits of 2^n, consider just last 10 digits at each iteration and repeat it for n-1 iterations.
Note:
With this approach, the biggest number you'll get during the calculation can be of 11 digits ~ 10^11, while for a 64-bit machine the max value is ~ 2^64 = ~ 10^18
unsigned const number = minimum + (rand() % (maximum - minimum + 1))
I know how to (easily) generate a random number within a range such as from 0 to 100. But what about a random number from the full range of int (assume sizeof(int) == 4), that is from INT_MIN to INT_MAX, both inclusive?
I don't need this for cryptography or the like, but a approximately uniform distribution would be nice, and I need a lot of those numbers.
The approach I'm currently using is to generate 4 random numbers in the range from 0 to 255 (inclusive) and do some messy casting and bit manipulations. I wonder whether there's a better way.
On my system RAND_MAX is 32767 which is 15 bits. So for a 32-bit unsigned just call three times and shift, or, mask etc.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void){
unsigned rando, i;
srand((unsigned)time(NULL));
for (i = 0; i < 3; i++) {
rando = ((unsigned)rand() << 17) | ((unsigned)rand() << 2) | ((unsigned)rand() & 3);
printf("%u\n", rando);
}
return 0;
}
Program output:
3294784390
3748022412
4088204778
For reference I'm adding what I've been using:
int random_int(void) {
assert(sizeof(unsigned int) == sizeof(int));
unsigned int accum = 0;
size_t i = 0;
for (; i < sizeof(int); ++i) {
i <<= 8;
i |= rand() & 0x100;
}
// Attention: Implementation defined!
return (int) accum;
}
But I like Weather Vane's solution better because it uses fewer rand() calls and thus makes more use of the (hopefully good) distribution generated by it.
We should be able to do something that works no matter what the range of rand() or what size result we're looking for just by accumulating enough bits to fill a given type:
// can be any unsigned type.
typedef uint32_t uint_type;
#define RAND_UINT_MAX ((uint_type) -1)
uint_type rand_uint(void)
{
// these are all constant and factor is likely a power of two.
// therefore, the compiler has enough information to unroll
// the loop and can use an immediate form shl in-place of mul.
uint_type factor = (uint_type) RAND_MAX + 1;
uint_type factor_to_k = 1;
uint_type cutoff = factor ? RAND_UINT_MAX / factor : 0;
uint_type result = 0;
while ( 1 ) {
result += rand() * factor_to_k;
if (factor_to_k <= cutoff)
factor_to_k *= factor;
else
return result;
}
}
Note: Makes the minimum number of calls to rand() necessary to populate all bits.
Let's verify this gives a uniform distribution.
At this point we could just cast the result of rand_uint() to type int and be done, but it's more useful to get output in a specified range. The problem is: How do we reach INT_MAX when the operands are of type int?
Well... We can't. We'll need to use a type with greater range:
int uniform_int_distribution(int min, int max)
{
// [0,1) -> [min,max]
double canonical = rand_uint() / (RAND_UINT_MAX + 1.0);
return floor(canonical * (1.0 + max - min) + min);
}
As a final note, it may be worthwhile to implement the random function in terms of type double instead, i.e., accumulate enough bits for DBL_MANT_DIG and return a result in the range [0,1). In fact this is what std::generate_canonical does.