C - Trouble with simple modulus table, it isn't so simple [closed] - c

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I've been crunching through Kernighan and Ritchie "The C Programming Language" and read that x mod y == x & y-1. So, I worked it out with pencil and paper, and worked fine, so then I tried to test it and here is the problem:
Code:
#include <stdio.h>
main()
{
int i, j;
for(i = 1; i < 10; i++){
for(j = 1; j < 10; j++)
printf("%3d",i & j-1);
printf("\n");
}
}
Gives the output:
0 1 0 1 0 1 0 1 0
0 0 2 2 0 0 2 2 0
0 1 2 3 0 1 2 3 0
0 0 0 0 4 4 4 4 0
0 1 0 1 4 5 4 5 0
0 0 2 2 4 4 6 6 0
0 1 2 3 4 5 6 7 0
0 0 0 0 0 0 0 0 8
0 1 0 1 0 1 0 1 8
and
#include <stdio.h>
main()
{
int i, j;
for(i = 1; i < 10; i++){
for(j = 1; j < 10; j++)
printf("%3d",i % j);
printf("\n");
}
}
gives the output:
0 1 1 1 1 1 1 1 1
0 0 2 2 2 2 2 2 2
0 1 0 3 3 3 3 3 3
0 0 1 0 4 4 4 4 4
0 1 2 1 0 5 5 5 5
0 0 0 2 1 0 6 6 6
0 1 1 3 2 1 0 7 7
0 0 2 0 3 2 1 0 8
0 1 0 1 4 3 2 1 0
Notice, the only change was the % that became &.
Any input would be much appreciated

The equation
x mod y == x & y-1
is only correct for y a power of 2.
If y = 2^k, the binary representaion of y is one 1-bit followed by k 0-bits (and preceded by a number of 0-bits depending on the width of the type), and the representation of y-1 is k 1-bits (preceded by 0s).
Then if you write x = q*y + r with 0 <= r < y, the binary representation of r needs at most k bits, and the last k bits of q*y are all 0, so the remainder of x modulo y consists of the least significant k bits of x, which are obtained by the bitwise and with y-1.
For an odd y > 1, y-1 is even, and so x & y-1 is always even, hence (y+1) % y == 1 != (y+1) & (y-1). For even y not a power of 2, replace 1 with the power of 2 corresponding to the lowest set bit of y in y+1.

Related

Matlab array that decreases from the center

I've been trying to make a 2-dimensional array that has the largest number in the center, and numbers around it decrement by one like this:
[0 0 0 0 0 0 0;
0 1 1 1 1 1 0;
0 1 2 2 2 1 0;
0 1 2 3 2 1 0;
0 1 2 2 2 1 0;
0 1 1 1 1 1 0;
0 0 0 0 0 0 0]
Any help?
This is easy using implicit expansion:
M = 7; % desired size. Assumed to be odd
t = [0:(M-1)/2 (M-3)/2:-1:0].';
result = min(t, t.');
Alternatively, you can use the gallery function with the 'minij' option to produce one quadrant of the result, and then extend symmetrically:
M = 7; % desired size. Assumed to be odd
result = gallery('minij',(M+1)/2)-1;
result = [result result(:,end-1:-1:1)];
result = [result; result(end-1:-1:1,:)];
Another approach, using padarray from the Image Processing toolbox:
result = 0;
for k = 1:(M-1)/2;
result = padarray(result+1, [1 1]);
end

My code to calculate in factorial (using recursion) works up to 24 but shows incorrect answers after that in c. Please check

#include <stdio.h>
int main()
{
int n, t, rem, i, j, k;
scanf("%d", &t);
int ans[t], integer[1000];
for(i=0; i<t; i++)
{
int count=0;
scanf("%d", &n);
for(j=0; j<1000; j++)
{
integer[j]=0;
}
for(j=0, k=n; k>0; k/=10, j++)
{
integer[j]=k%10;
count++;
}
factorial(n, count, integer);
}
return 0;
}
void factorial(int n, int count, int* integer)
{
int i, j, k, rem=0, temp;
if(n==1)
{
for(i=count-1; i>=0; i--)
{
printf("%d", integer[i]);
}
printf("\n");
return;
}
else
{
for(i=0; i<count; i++)
{
temp=integer[i]*(n-1);
integer[i]=(temp%10)+rem;
rem=temp/10;
if(i==count-1)
{
if(rem!=0)
{
for(j=0, k=rem; k>0; k/=10, j++)
{
integer[count]=k%10;
count++;
}
break;
}
}
}
factorial(n-1, count, integer);
}
}
Explanation : I save the numbers in the inverse way
ex input :100
integer saved in array : 0 0 1 0 0 0 0...
then as factorial function is called it takes n=100, count=3, and the integer array as input.
we multipy the first element of the array with n-1 and carry on the remainder... this carries on until the whole integer array is multiplied with 99, then we again call factorial thus multiplying the array with 98 and so on until we reach 1 where we ultimately print the answer.
Problem : the code gives correct result upto 24 only and gives wrong output thereafter.
you suppose each element in integer is between 0 and 9 but this is not the case, adding a space after writing a digit indicates the problem, for instance computing fact from 1 up to 22 :
1
2
6
2 4
1 2 0
7 2 0
5 0 4 0
4 0 3 2 0
3 6 2 8 8 0
3 6 2 8 8 0 0
3 9 9 1 6 8 0 0
4 7 8 10 0 1 6 0 0 <<< wrong value for !12
6 2 2 7 0 2 0 8 0 0
8 7 1 7 8 2 9 1 2 0 0
1 3 0 7 6 7 4 3 6 8 0 0 0
2 0 9 2 2 7 8 9 8 8 8 0 0 0
3 5 5 6 8 7 4 2 8 0 9 6 0 0 0
6 4 0 2 3 7 3 7 0 5 7 2 8 0 0 0
1 2 1 6 4 5 0 10 0 4 0 8 8 3 2 0 0 0 <<< wrong value for 19
2 4 3 2 9 0 2 0 0 8 1 7 6 6 4 0 0 0 0
5 1 0 9 0 9 4 2 1 7 1 7 0 9 4 4 0 0 0 0
1 1 2 3 10 0 0 7 2 7 7 7 7 6 0 7 6 8 0 0 0 0 <<< wrong value for 22
So your problem comes because you do not manage enough the carry
Example in 4 7 8 10 0 1 6 0 0 handling in a right way produces 4 7 9 0 0 1 6 0 0 as expected
To solve that in factorial after the line
rem=temp/10;
add
if (integer[i] > 9)
{
rem += integer[i] / 10;
integer[i] %= 10;
}
Out of that :
ans[t] is useless
when you use scanf or equivalent function check the result to be sure a valid value was enter
if the result use more that 1000 digit in base 10 you will write out of integer
the calculation is overflowing the capability of an integer.

MATLAB find first elements in columns of array

Within the context of writing a certain function, I have the following example matrix:
temp =
1 2 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
I want to obtain an array whose each element indicates the number of the element out of all non-zero elements which starts that column. If a column is empty, the element should correspond to the next non-empty column. For the matrix temp, the result would be:
result = [1 3 5 5 5 6]
Because the first non-zero element starts the first column, the third starts the second column, the fifth starts the fifth column and the sixth starts the sixth column.
How can I do this operation for any general matrix (one which may or may not contain empty columns) in a vectorized way?
Code:
temp = [1 2 0 0 1 0; 1 0 0 0 0 0; 0 1 0 0 0 1]
t10 = temp~=0
l2 = cumsum(t10(end:-1:1))
temp2 = reshape(l2(end)-l2(end:-1:1)+1, size(temp))
result = temp2(1,:)
Output:
temp =
1 2 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
t10 =
1 1 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
l2 =
1 1 1 1 1 2 2 2 2 2 2 2 3 3 4 4 5 6
temp2 =
1 3 5 5 5 6
2 4 5 5 6 6
3 4 5 5 6 6
result =
1 3 5 5 5 6
Printing values of each step may be clearer than my explanation. Basically we use cumsum to get the IDs of the non-zero elements. As you need to know the ID before reaching the element, a reversed cumsum will do. Then the only thing left is to reverse the ID numbers back.
Here's another way:
temp = [1 2 0 0 1 0; 1 0 0 0 0 0; 0 1 0 0 0 1]; % data
[~, c] = find(temp); % col indices of nonzero elements
result = accumarray(c, 1:numel(c), [], #min, NaN).'; % index, among all nonzero
% values, of the first nonzero value of each col; or NaN if none exists
result = cummin(result, 'reverse'); % fill NaN's using backwards cumulative maximum

Create a "pyramid" matrix

Say I'm given a symmetric row vector with an odd length where each element is smaller than the next one in the first half of the vector and each element is bigger than the next one in the second half and the middle element is the biggest. (e.g [1 2 3 2 1] or [10 20 50 20 10]).
I want to create a square matrix where this row vector is its middle row and the equivalent column vector (v') is its middle column and each other row or column is a reduced version of the given vector according to the middle element in this row or column. And when there are no more "original elements" we put 0.
Examples:
if v = [1 2 3 2 1] we get
0 0 1 0 0
0 1 2 1 0
1 2 3 2 1
0 1 2 1 0
0 0 1 0 0
if v = [3 5 3] we get
0 3 0
3 5 3
0 3 0
What I did so far: I managed to create a matrix with v as the middle row and v' as the middle column with this code I wrote:
s = length(vector);
matrix= zeros(s);
matrix(round(s/2),:) = vector;
matrix(:, round(s/2)) = vector';
but got stuck with assigning the other values.
A more hands-on approach is to produce your matrix as a mosaic, starting from a hankel matrix. For performance comparison, here's a version using the same format as #Divakar's solution:
function out=pyramid_hankel(v)
%I suggest checking v here
%it should be odd in length and a palindrome
i0=ceil(length(v)/2);
v2=v(i0:end);
Mtmp=hankel(v2);
out=zeros(length(v));
out(i0:end,i0:end)=Mtmp;
out(1:i0-1,i0:end)=flipud(Mtmp(2:end,:));
out(:,1:i0-1)=fliplr(out(:,i0+1:end));
>> pyramid_hankel([1 2 3 2 1])
ans =
0 0 1 0 0
0 1 2 1 0
1 2 3 2 1
0 1 2 1 0
0 0 1 0 0
For v=[1 2 3 2 1] the starting block is hankel([3 2 1]), which is
ans =
3 2 1
2 1 0
1 0 0
From here it should be clear what's happening.
Here's one approach -
function out = pyramid(v)
hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
upper_part = cumsum(bsxfun(#le,(hlen:-1:1)',updown_vec)); %//'
out = [upper_part ; flipud(upper_part(1:end-1,:))];
out = changem(out,v,updown_vec);
Here's another approach, sort of simpler maybe -
function out = pyramid_v2(v)
hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
mask = bsxfun(#le,([hlen:-1:1 2:hlen])',updown_vec); %//'
M = double(mask);
M(hlen+1:end,:) = -1;
out = changem(cumsum(M).*mask,v,updown_vec);
Sample runs -
>> v = [1 2 3 2 1];
>> pyramid(v)
ans =
0 0 1 0 0
0 1 2 1 0
1 2 3 2 1
0 1 2 1 0
0 0 1 0 0
>> v = [3 5 3];
>> pyramid(v)
ans =
0 3 0
3 5 3
0 3 0
>> v = [99,3,78,55,78,3,99];
>> pyramid(v)
ans =
0 0 0 99 0 0 0
0 0 99 3 99 0 0
0 99 3 78 3 99 0
99 3 78 55 78 3 99
0 99 3 78 3 99 0
0 0 99 3 99 0 0
0 0 0 99 0 0 0
Here's another approach:
v = [1 2 3 2 1]; %// symmetric, odd size
m = (numel(v)-1)/2;
w = [0 v(1:m+1)];
t = abs(-m:m);
result = w(max(m+2-bsxfun(#plus, t, t.'),1));

Matlab: vectorize assignment of values in matrix based on index

Apologies in advance if this question is a duplicate, or if the solution to this question is very straightforward in Matlab. I have a M x N matrix A, a 1 x M vector ind, and another vector val. For example,
A = zeros(6,5);
ind = [3 4 2 4 2 3];
val = [1 2 3];
I would like to vectorize the following code:
for i = 1 : size(A,1)
A(i, ind(i)-1 : ind(i)+1) = val;
end
>> A
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0
That is, for row i of A, I want to insert the vector val in a certain location, as specificied by the i'th entry of ind. What's the best way to do this in Matlab without a for loop?
It can be done using bsxfun's masking capability: build a mask telling where the values will be placed, and then fill those values in. In doing this, it's easier to work with columns instead of rows (because of Matlab's column major order), and transpose at the end.
The code below determines the minimum number of columns in the final A so that all values fit at the specified positions.
Your example applies a displacement of -1 with respect to ind. The code includes a generic displacement, which can be modified.
%// Data
ind = [3 4 2 4 2 3]; %// indices
val = [1 2 3]; %// values
d = -1; %// displacement for indices. -1 in your example
%// Let's go
n = numel(val);
m = numel(ind);
N = max(ind-1) + n + d; %// number of rows in A (rows before transposition)
mask = bsxfun(#ge, (1:N).', ind+d) & bsxfun(#le, (1:N).', ind+n-1+d); %// build mask
A = zeros(size(mask)); %/// define A with zeros
A(mask) = repmat(val(:), m, 1); %// fill in values as indicated by mask
A = A.'; %// transpose
Result in your example:
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0
Result with d = 0 (no displacement):
A =
0 0 1 2 3 0
0 0 0 1 2 3
0 1 2 3 0 0
0 0 0 1 2 3
0 1 2 3 0 0
0 0 1 2 3 0
If you can handle a bit of bsxfun overdose, here's one with bsxfun's adding capability -
N = numel(ind);
A(bsxfun(#plus,N*[-1:1]',(ind-1)*N + [1:N])) = repmat(val(:),1,N)
Sample run -
>> ind
ind =
3 4 2 4 2 3
>> val
val =
1 2 3
>> A = zeros(6,5);
>> N = numel(ind);
>> A(bsxfun(#plus,N*[-1:1]',(ind-1)*N + [1:N])) = repmat(val(:),1,N)
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0

Resources