I need to make a formula that gives you the truth table for a variable number of columns.
Example
The current recommended answer did not work for me. For a simpler method, I'd recommend the following formula:
=IF(MOD(FLOOR((ROW()-ROW(TopRight))/(2^(COLUMN(TopRight)-COLUMN())), 1),2)=0,0,1)
Where TopRight is the top right cell of the truth table.
For instance, if you're creating a truth table with 8 entries that starts in A3, replace TopRight with $H$3, then drag the formula across and down.
A basic explanation of what's going on: In truth tables, the rows alternate 1 or 0 every 2 ^ n number of rows, where n is the the number of columns that the given column is away from the rightmost column.
Replace the FirstCell with a static reference to the cell that contains the first 2^1 value e.g. $D$1 for a 4-bit table (16 values) and autofill to the rest of the grid (in the example A1:D16)
=IF(MOD(ROW()-ROW(FirstCell),POWER(2, ((COLUMN() - COLUMN(FirstCell)) * -1) + 1)) >= (POWER(2, ((COLUMN() - COLUMN(FirstCell)) * -1) + 1) / 2),1,0)
The logic behind this is:
If the current row modulus 2 power current column (* -1 as the first value is in the last column and + 1 because it starts from 0) is greater or equal to half of 2 power current column, put the value as 1, else put the value as 0.
The other answers might make Boole sad. This one aims to be more boolean.
You need to populate the first row (2) with 0's
For the LSB column (D) - Invert:
=NOT(D2)*1 (formula for cell D3, copied to D4:D17)
That will invert the value from the row above. The *1 numification is necessary to avoid seeing TRUE or FALSE
For all other columns - Add:
=XOR(AND(D2:$D2),C2)*1 (formula for cell C3, copied to all cells A3:C17)
For an ADD function, you want to XOR the value above in the column with the result of ANDing all the bits in all the columns to the right of it. (In other words: if all the bits to the right of the bit above are 1, then you should flip the value from the bit above. This ADD formula works for any number of columns.)
The AND range is referenced to one row up and one col right, to the $D LSB column, also one row up. So the $D anchor for the LSB column allows copying to any other column
Again, *1 is used for numification of the resulting TRUE/FALSE
Here's a Microsoft 365 one-liner:
=TRANSPOSE(LET(n,5,m,2^n,x,SEQUENCE(n,m,0),y,FLOOR(x/m,1),z,FLOOR((x-y*m)/2^(n-1-y),1),MOD(z,2)))
n is the number of columns needed, m then stores the length of each column.
The formula finds the row of x and stores the value in y, and then successively halves each row into the correct format, and outputs the result mod 2 to produce the truth table set of inputs.
TRANSPOSE is used because SEQUENCE places the numbers left-right, top-bottom.
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
.....
remember the numbers are only 0 or 1.
for column D: D2=1-D1
for column C: C2=IF(D1=1,1-D1,D1)
for column B: B2=IF((C1=1)*(D1=1),1-B1, B1)
.....
After did this, copy the numbers without formulas for your truth table to avoid Excel calculation.
Related
I need your help with this problem I'm facing using Excel. Basically I need to populate a table, or better, a given group of cells (dimensions 3x3), and my starting point is:
row numb. column name. value
2 A 10
3 C 4
4 B 20
so I would need to obtain a group of cell like this:
1 A B C
2 10 0 0
3 0 0 4
4 0 20 0
where the cells that have no value can be 0 or whatever. In other words, I have the coordinates where I need to insert the value, and I need to be insert the value corresponding to the coordinates in the right cell.
I already tried many times using functions like MATCH, VLOOKUP and INDEX (also ROW and COLUMN) but without success, because it inserts the correct values but also other combinations of coordinates that I don't want.
My idea was to start from cell A2 and, with the formula, check if there's a match with the coordinates of row and column in the data, and finally print the value.
PS: I would prefer to avoid VBA.
Try this array formula: (Of course, change your cell ranges as necessary)
= IFERROR(INDEX($G$2:$G$4,MATCH(TRUE,ADDRESS(ROW(),COLUMN(),4)=($F$2:$F$4&$E$2:$E$4),0)),0)
Note this is an array formula, so you must press Ctrl+Shift+Enter rather than just Enter after typing the formula.
See working example below.
I want to write numbers in excel starting from 000001 till 999999
I have done like this =TEXT(A2,"000001") but i am not been able to generate series even though not able to separate this in different attributes
Further I want to distribute each number in each different cell for example like this
A B C D E F G
000001 0 0 0 0 0 1
000002 0 0 0 0 0 2
till
999999 9 9 9 9 9 9
Use following formuls to B1 cell and drag then right and down as needed.
=MID($A1,COLUMNS($A$1:A$1),1)
See the screenshot.
Here is a better way:
In cell A1, type 1.
Select A1 and from Home tab, choose Fill > Series (top-right).
Choose Columns; Linear; set Step Value to 1 and Stop Value to 999999 or whatever you want. Click OK.
Use AutoFill feature to fill up to the number you want.
Right-click column A header and choose Format Cells.
Choose Custom formatting and type 000000 in the custom format type textbox.
Click OK. Your cells will now show 000001, 000002, ... and so on.
In cell B1, type the following formula:
=INT(MOD($A1/(POWER(10, 7- COLUMN())), 10))
Copy B1 to columns C1 through G1.
Copy range B1:G1 to all subsequent rows B2:G999999 or whatever.
Notes
One advantage of this approach is that column A is numeric, not text, so you can enter any 6-digit (or less) integer in it directly from keyboard and the cells will update themselves correctly.
Column A will adjust number of leading zeros automatically for 6-digits or smaller numbers.
The formula simply divides the number in column A by 10, 100, 1000 and so on and then takes remainder by 10, to get the corresponding digit at that decimal place.
You can easily modify this formula to work with larger or smaller numbers. You simply need to replace 7 by (maximum number of digits in your number + 1).
Might be a bit easier with a VBA macro. Right-click the sheet tab, select View Code, paste the below code, and Run (F5)
Sub fill()
[a1:a999999] = "=text(row(), ""000000"")"
[b1:g999999] = "=mid($a1, column()-1, 1)"
End Sub
(Write this formula in Column A and extend it down to row 999999)
generating the series:
=RIGHT(10^6, 6-LEN(ROW(A1)))&ROW(A1)
Write this formula in Column B and extend it to Column G, then
extend the range of B1:G1 to B999999:G999999
Distributing digits
=MID($A1,COLUMN(A1),1)
how can I merge two columns of data into one like the following:
Col1 Col2 Col3
========================
A 1 A
B 2 1
C 3 B
2
C
3
You can use the following formula in column D as per my example. Keep in mind to increase the $A$1:$B$6 range according to your data.
=INDEX($A$1:$B$6,INT((ROWS(D$2:D2)-1)/2)+1,MOD(ROWS(D$2:D2)-1,2)+1)
Result:
Thank you to #Koby Douek for the answer. Just an addition--if you are using Open Office Calc, you replace the commas with semi-colons.
=INDEX($A$1:$B$6;INT((ROWS(D$2:D2)-1)/2)+1;MOD(ROWS(D$2:D2)-1;2)+1)
Expanding #koby Douek's answer to more columns and explaining some of the terms
Original Code for 2 columns to 1 alternating
=INDEX($A$1:$B$6,INT((ROWS(D$2:D2)-1)/2)+1,MOD(ROWS(D$2:D2)-1,2)+1)
$A$1:$B$6 Defines the columns and rows to source the final set of data from, the $s are only present to keep the formula from changing the columns and rows selects if it is copied and pasted or dragged.
To extend to work on any values you dump into the columns instead of having to expand the range every time it should be amended to $A:$B or A:B so you can easily copy it to other sets of columns and create new merges, but it will also give the 1st value in every column as one of the alternating values so if you instead have headers you would be able to do this by instead using a large number so $A$1:$B$99999 or A$1:B$99999 if you want to past and move the columns ymmv which is better by situation.
lets assume you are fine including the values in the 1st row
This changes the formula to
=INDEX($A:$B,INT((ROWS(D$2:D2)-1)/2)+1,MOD(ROWS(D$2:D2)-1,2)+1)
Now on to D$2:D2
This is the row that is being used to calculate the difference between the current row the formula is in (D2) and the reference row (D$2) The important thing to make sure you do is to set the reference row number to the 1st row you will be putting values in, so if your 1st row is a header in the sort column you will use the 2nd row as the reference, if your values in the combined column D begin on the 3rd row then the reference row would be D$3
Since I like the more general form where the 1st row isn't a header row I'll use D$1:D1 but you could still mix source rows without headers into a combined row with a header of as many rows as you like just by incrementing that reference row number to be the 1st row where your values should begin.
This changes the formula to
=INDEX($A:$B,INT((ROWS(D$1:D1)-1)/2)+1,MOD(ROWS(D$1:D1)-1,2)+1)
Now INT((ROWS(D$1:D1)-1)/2)+1 and MOD(ROWS(D$1:D1)-1,2)+1
INT returns an integer value so any decimal places are dropped, it essentially functions like rounding down to the nearest whole number
MOD functions by returning the remainder of a division, it's result will be a whole number between 0 and n-1 where n is the number we are dividing by. (eg: 0/3=0; 1/3=1; 2/3=2; 3/3=0; 4/3=1 ... etc)
So -1)/2)+1 and -1,2)+1
the first value is again the difference between the current row and the reference row. but D$1:D1 is going to be the count of the rows, which is 1 so we have to correct for the rows count starting at 1 instead of 0 which would throw off our calculations, so both are using the -1 to reduce the count of the rows by 1
in the case of /2 and ,2 both are because we are dividing by 2 in the first statement it's a normal division by 2 /2 in the modulus statement it's an argument of the Mod function so ,2
finally we need to add 1 using +1 to correct for the index's need to have a value series which begins at 1.
INT((ROWS(D$2:D2)-1)/2)+1 is finding the row number to select the value from.
MOD(ROWS(D$1:D1)-1,2)+1 is finding the column number to select the value from
Thus we can change /2 and ,2 to /3 and ,3 to do this with 3 columns
This yields:
=INDEX($A:$B,INT((ROWS(D$1:D1)-1)/3)+1,MOD(ROWS(D$1:D1)-1,3)+1)
So maybe that's the confusing way to look at it but it's closer to how my mind works on it. Here is an alternative view:
=INDEX([RANGE],[ROW_#],[COLUMN_#]) returns the value from a range of rows and columns
Using the example:
=INDEX($A:$B,INT((ROWS(D$1:D1)-1)/3)+1,MOD(ROWS(D$1:D1)-1,3)+1)
[RANGE] = $A:$B this is the range of source columns.
[ROW_#] = INT((ROWS(D$1:D1)-1)/3)+1
INT([VALUE_A])+1 returns an integer value so any decimal places are dropped. Then adds one to it. we add one to the value because the result of the next steps will be 1 less than the value we need.
[Value_A] = (ROWS(D$1:D1)-1)/3
ROWS(D$1:D1) returns the number of rows in the Range to the current row in the results column, we use D$1 to designate the row number where the values in the results column begin. D1 is the current row in the results column giving us a range from the source row, allowing us to count the rows. we have to subtract 1 from this value using -1 to get the difference between the source and current. This is then divided by /3 because we have three columns we want to look through in this example so we only change rows when the result is divisible by 3. the INT drops any decimal places as mentioned so it only increments when cleanly divisible by 3.
[COLUMN_#] = MOD(ROWS(D$1:D1)-1,3)+1
MOD([VALUE],[Divisor])+1 returns the remainder of the value when divided by the divisor.
Using the example:
MOD(ROWS(D$1:D1)-1,3)+1
In this case we still divide by 3 but it's an argument to the MOD function, we still need to count the number of rows and subtract 1 before dividing it, this will return a 0, 1, or 2 for the column, but as above we are shifted backwards by 1 as the column numbers begin with the number 1, so as before we must add 1
And here we add column A and D
two different formulas depending on if you add the formula to an odd row or an even row.
https://1drv.ms/x/s!AncAhUkdErOkguUaToQkVkl5Qw-l_g?e=5d9gVM
Odd Start row
=INDEX($A$2:$D$9;ROUND(ROW(A1)/2;0);IF(MOD(ROW()-ROW($A$2);2)=1;4;1))
Even Start row
=INDEX($A$2:$D$9;ROUND(ROW(A1)/2;0);IF(MOD(ROW()-ROW($A$1);2)=1;4;1))
What is A1 in the picture is the cell directly above your first data cell.
If you want to place it on a different sheet you just add the sheet name:
=INDEX(MySheet!$A$2:$D$9;ROUND(ROW(MySheet!A1)/2;0);IF(MOD(ROW()-ROW(MySheet!$A$2);2)=1;4;1))
=INDEX(MySheet!$A$2:$D$9;ROUND(ROW(MySheet!A1)/2;0);IF(MOD(ROW()-ROW(MySheet!$A$1);2)=1;4;1))
I have a spreadsheet where data is spread in alternated columns. Columns A, C and E are flags indicating if the adjacent column has a valid data.
It is like this:
A B C D E F
1 1 32 0 67 1 34
The goal is to sum values where its left adjacent is 1. In this example, the sum should be 66, as A and E are both 1 and C is 0.
I can get an array with 1's and 0's indicating if a flag column is set or not:
=MOD(COLUMN(A1:F1),2)*A1:F1
And that gives me
{1, 0, 0, 0, 1, 0}
The thing is that I don't know what I can do from here. If I could slide all the data (by inserting a 0 at the beginning and removing the 0 at the last position), I could SUMPRODUCT it and get the result.
By the way, I can't use macros...
Ideas?
Notice that Formula bellow has two cell ranges one starts at column A the other at B.
=SUMIF(A1:F1,1,B1:G1)
If you are not famliar with SUMIF then what you need to know about this is that first term A1:F1 is where formula checks values for a condition. What condition you might ask values that equal to seconds term in this case =1. Lastly last term has the values that need to be sumed.
Also since you may have issuse of having 1 in an Even column( where you'd expect value not you condition), heve is a formula that makes sure that your 1 & 0 condition is in correct Column:
=SUM(IF((A1:F1=1)*ISODD(COLUMN(A1:F1)),B1:G1,0))
Simple version:
=SUM(A1*B1,C1*D1,E1*F1)
As 0 multiplied by anything is always zero then this only sums the columns preceded by a 1.
I have a table like this:
Length 4
year 1 2 3 4 5
A 100 400 300 200 400
B
And in column B I want a sum of A from the past [length] years. For this I figured I needed an OFFSET, so my function is (for year 2):
=SUM.IF(OFFSET(B3;0;0;1;-B1);">0")
The if statement is used so it doesn't give an error when it reaches the edge of the table, but for years 2 and 3 the OFFSET range is outside of the worksheet so it doesn't work. How can I specify a condition that it just doesn't sum anything that isn't on the worksheet?
In A2:
=SUM(INDEX(1:1,COLUMNS($A:A)):INDEX(1:1,MAX(1,COLUMNS($A:A)-3)))
Copy to the right as required.
Regards
Ok, it was hard to decypher the question:
When you ask column B, I guess you mean row 4, right?
You don't need SUMIF, because SUM doesn't count empty cells or cells
with non-numeric value.
The reference to the length value should be absolute, so it doesn't
change as you copy the formula:
$B$1
OFFSET's Width value cannot be negative, rather have the Cols value =
-[Length]:
OFFSET(C3;0; -$B$1...
(Now you are referencing 4 columns left to C3)
Make sure it is not out of the worksheet by not letting more than the [column number of the given cell minus 1] be referenced left from the cell:
OFFSET(C3;0; -MIN(COLUMN(C3)-1;$B$1)...
That is the starting point of your range to sum; you should sum it
up to recent year's value. So the correct formula in C4 is:
=SUM(OFFSET(C3;0;-MIN(COLUMN(C3)-1;$B$1)):C3)