I have 2 variables, width and height as integers. Any of these can be positive or negative (not zero). So naturally there are 4 cases;
width > 0 && height > 0
width > 0 && height < 0
width < 0 && height > 0
width < 0 && height < 0
Now I want to take different action on each of these 4 cases without using 4 if statements.
Is there a way to aggregate these cases so that it can be put as a simple switch case
switch( aggregate ){
case 1:
case 2:
case 3:
case 4:
}
If there is no better way than using if for each then in 3D space you have 3 lengths (x,y,z) and there will be 27 if blocks.
I'm using javascript if that matters.
In javascript this is quite easy, just turn the condition upside down:
switch(true)
{
case (width > 0 && height > 0):
break;
case (width > 0 && height < 0):
break;
case (width < 0 && height > 0):
break;
case (width < 0 && height < 0):
break;
default:
}
This also works in VB6/VBA but not in many other languaguages like C++ and C#.
Here's a simple proof: http://jsfiddle.net/avuxj/
You could treat each of your conditions (width positive, height positive) as a single boolean attribute and combine them to binary number and switch over it.
Pseudocode:
int v = (width > 0 ? 0 : 1) << 1 | (height > 0 ? 0 : 1) << 0;
switch (v) {
case 0b00:
// width < 0 && height < 0;
break;
case 0b01:
// width < 0 && height > 0;
break;
case 0b10:
// width > 0 && height < 0
break;
case 0b11:
// width > 0 && height > 0
break;
}
If the language of your choice doesn't have binary numeric literals, then it's not as readable, but you might be able to fix that with comments.
Also note that languages that support interpreting true as 1 and false as 0 will help make the int v = ... line shorter.
You could do
var bits=0;
if(width > 0) {
bits+=1;
}
if(height > 0) {
bits+=2;
}
switch{bits} {
case 0: //both negative
//something
break;
case 1: //width positive, height negative
//something
break;
case 2: //width negative, height positive
//something
break;
case 3: //both positive
//something
break;
}
Although it is all bit confusing. (Especially if You have 3 values). You can use variables to make Your code bit clearer.
var WIDTH_POSITIVE_BIT=1;
var HEIGHT_POSITIVE_BIT=2;
var bits=0;
if(width > 0) {
bits+=WIDTH_POSITIVE_BIT;
}
if(height > 0) {
bits+=HEIGHT_POSITIVE_BIT;
}
switch{bits} {
case 0: //both negative
//something
break;
case WIDTH_POSITIVE_BIT: //width positive, height negative
//something
break;
case HEIGHT_POSITIVE_BIT: //width negative, height positive
//something
break;
case WIDTH_POSITIVE_BIT+HEIGHT_POSITIVE_BIT: //both positive
//something
break;
}
I'd say that this does not help to make the code much clearer.
Can't do this without adding a little overhead.
s = ( width < 0 ) ? 0 : 1;
s += ( height < 0 ) ? 0 : 2;
switch(s) {
case 0: // 00 => both < 0
case 1: // 01 => width > 0, height < 0
case 2: // 10 => width < 0, height > 0
case 3: // 11 => both > 0
}
And this could work for a 3D case:
s = ( width < 0 ) ? 0 : 1; //First bit for width
s += ( height < 0 ) ? 0 : 2; //Second bit for height
s += ( depth < 0 ) ? 0 : 4; //Third bit for depth
switch(s) {
case 0: // 0 0 0
case 1: // 0 0 1
case 2: // 0 1 0
case 3: // 0 1 1
case 4: // 1 0 0
case 5: // 1 0 1
case 6: // 1 1 0
case 7: // 1 1 1
}
Of course assuming you can't have a 0 dimension.
Several answers are logically correct. If you were doing this in C it would be:
s = ((width<0)<<1) | (height<0);
switch(s) {
....
}
This can make a huge difference. I have code that combines 9 conditions into a switch like this. The switch gets turned into a jump table and is much faster than evaluating a bunch of conditions. There is no branching, just the jump table. I can't really speak to anything java or java script though.
You may also do nested if statements:
if (witdh<0) {
if (height<0) {
// both negative
}
else {
// only width negative
}
}
else {
if (height<0) {
// only height negative
}
else {
// both positive
}
}
I find mashing the condition bits together and using a switch to be more readable - especially if the number of conditions grows.
Related
Below is a code for the problem of CLIMBING STAIRS https://leetcode.com/problems/climbing-stairs/
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n,0);
dp[0] = 1;
dp[1] = 2;
for(int i=2;i<n;i++){
dp[i] = dp[i-2]+dp[i-1];
}
return dp[n-1];
}
};
The code gives a RUNTIME ERROR of HEAP BUFFER OVERFLOW.
Looking at the code , if n==1 the code should return dp[n-1] i.e. dp[0] ,
but that does not seem to be the case.
I'm guessing the issue maybe related to access of elements in vector.
Can anyone please explain what could be the issue here ??
if n==1 the code should return dp[n-1] i.e. dp[0] , but that does not seem to be the case.
Yes.
But when n == 1, you call
dp[1] = 2;
so you access the second element when you have only one element.
And what about the case n <= 0 ?
So, maybe
int climbStairs(int n) {
if ( 0 >= 0 ) {
return ???;
} else if ( 1 == n ) {
return 1;
} else {
vector<int> dp(n,0);
dp[0] = 1;
dp[1] = 2;
for(int i=2;i<n;i++){
dp[i] = dp[i-2]+dp[i-1];
}
return dp[n-1];
}
}
The problem states the constraints are
1 <= n <= 45
You're going out of range when n is 1 (i.e. you only have dp[0] that scenario)
I'm currently using the intel SIMD function: _mm_cmplt_ps( V1, V2 ).
The function returns a vector containing the results of each component test. Based on if V1 components are less than V2 components, example:
XMVECTOR Result;
Result.x = (V1.x < V2.x) ? 0xFFFFFFFF : 0;
Result.y = (V1.y < V2.y) ? 0xFFFFFFFF : 0;
Result.z = (V1.z < V2.z) ? 0xFFFFFFFF : 0;
Result.w = (V1.w < V2.w) ? 0xFFFFFFFF : 0;
return Result;
However is there a function like this that returns 1 or 0 instead? A function that uses SIMD and no workarounds because it is supposed to be optimized + vectorized.
You can write that function yourself. It’s only 2 instructions:
// 1.0 for lanes where a < b, zero otherwise
inline __m128 compareLessThan_01( __m128 a, __m128 b )
{
const __m128 cmp = _mm_cmplt_ps( a, b );
return _mm_and_ps( cmp, _mm_set1_ps( 1.0f ) );
}
Here’s more generic version which returns either of the 2 values. It requires SSE 4.1 which is almost universally available by now with 97.94% of users, if you have to support SSE2-only, emulate with _mm_and_ps, _mm_andnot_ps, and _mm_or_ps.
// y for lanes where a < b, x otherwise
inline __m128 compareLessThan_xy( __m128 a, __m128 b, float x, float y )
{
const __m128 cmp = _mm_cmplt_ps( a, b );
return _mm_blendv_ps( _mm_set1_ps( x ), _mm_set1_ps( y ), cmp );
}
The DirectXMath no-intrinsics version of _mm_cmplt_ps is actually:
XMVECTORU32 Control = { { {
(V1.vector4_f32[0] < V2.vector4_f32[0]) ? 0xFFFFFFFF : 0,
(V1.vector4_f32[1] < V2.vector4_f32[1]) ? 0xFFFFFFFF : 0,
(V1.vector4_f32[2] < V2.vector4_f32[2]) ? 0xFFFFFFFF : 0,
(V1.vector4_f32[3] < V2.vector4_f32[3]) ? 0xFFFFFFFF : 0
} } };
return Control.v;
XMVECTOR is the same as __m128 which is 4 floats so it needs the alias to make sure it's writing integers.
I use _mm_movemask_ps for the "Control Register" version of DirectXMath functions. It just collects the top-most bit of each SIMD value.
int result = _mm_movemask_ps(_mm_cmplt_ps( V1, V2 ));
The lower nibble of result will contain bit patterns. A 1 bit for each value that passes the test, and a 0 bit for each value that fails the test. This could be used to reconstruct 1 vs. 0.
Given a binary matrix, we want to check if there exists a path across nodes on two ends, such as:
0 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 0
this case has a chain of one's from the first to the last row which is stretched over in some of the rows. Similarly, the result should be true even if there's a chain from left to the right column.
I thought about writing a recursively exploring function for each positive element through-out the top row and the left column. Could you suggest something better?
one of solutions would be to use Set:
Go through each row
If field value is 1 and one of its already visited neighbours is inside the Set, add its coordinates (x,y) to the Set
At the end, check if Set contains any coordinates from the last row - if so, there is a path.
as you didn't mention which language you would like to use, here's how it looks like in Javascript (ES6):
let matrix = '01000
01100
00110
00010'.split('\n').map((row) => { return row.split('') });
let set = new Set();
let cols = matrix[0].length;
let rows = matrix.length;
for(let col=0; col < cols; col++){
if(matrix[0][col] == '1'){
set.add(`0,{col}`);
}
}
for(let row=1; row < rows-1; row++){
for(let col=1; col < cols; col++){
if(matrix[row][col] == '1' &&
(set.has(`{row-1},{col-1}`) ||
set.has(`{row-1},{col}`) ||
set.has(`{row-1},{col+1}`) ||
set.has(`{row},{col-1}`))){
set.add(`{row},{col}`);
}
}
}
let row = rows-1;
for(let col=0; col < cols; col++){
if(matrix[row][col] == '1' &&
(set.has(`{row-1},{col-1}`) ||
set.has(`{row-1},{col}`) ||
set.has(`{row-1},{col+1}`) ||
set.has(`{row},{col-1}`))){
// HAS PATH
}
}
How do you fake conditionals that don't nest in a language that doesn't allow goto? I want to do the following:
if (condition1)
action1;
if (!condition1 && condition2)
action2;
if (!condition2 && condition3)
action3;
Without:
Needlessly evaluating any condition more than once.
Needlessly storing the result of any such evaluation in a variable.
Needlessly specifying more than once that any action should be performed.
The original snippet fails to meet requirement 1.
The following snippet fails to meet requirement 2:
if (condition1) {
action1;
c2 = false;
}
else if (c2 = condition2)
action2;
if (!c2 && condition3)
action3;
And the following snippet fails to meet requirement 3:
if (condition1) {
action1;
if (condition3)
action3;
}
else if (condition2)
action2;
else if (condition3)
action3;
EDIT:
It is impossible that condition1 and condition2 be true simultaneously.
It is impossible that condition2 and condition3 be true simultaneously.
Here is the original code (in JavaScript):
// If only the array of elements was specified,
// wrap it inside an object.
if (info.constructor !== Object)
info = {children: info};
// If no array of elements was specified, create
// an empty array of elements.
if (!info.children)
info.children = [];
// If, instead of an array of elements, we have
// a single element, wrap it inside an array.
if (info.children.constructor !== Array)
info.children = [info.children];
Truth Table
C1 C2 C3 Action
0 0 0 None
0 0 1 A3
0 1 0 A2
0 1 1 A2
1 0 0 A1
1 0 1 A1+A3
1 1 0 A1
1 1 1 A1
Is switch/case against the rules? :)
switch(C1*4 + C2*2 + C1) {
case 7: case 6: case 4: A1; break;
case 5: A1; A3; break;
case 3: case 2: A2; break;
case 1: A3; break;
}
So how do you do this with goto anyway? This immediately comes to mind, but doesn't have quite the same result:
if(condition1) {
action1;
goto a;
}
if(condition2) {
action2;
goto b;
}
a:
if(condition3) {
//This will run if condition1 && condition2 && condition3
action3;
}
b:
Either way, you do have a few tricks that can break out of nested "if"s. Try:
do {
if(condition1) {
action1;
} elseif(condition2) {
action2;
break;
}
if(condition3) {
action3;
}
} while(false);
It's essentially a goto, but...
That version will duplicate the goto construct that I imagined, rather than the one in the OP. Note that "return" works about the same, in case that looks cleaner in your code (and it might be able to push the hack a bit further by returning a boolean).
Attempts 1 & 2:
Note: Removed first attempts to cut down on question size. See community wiki for previous attempts.
Attempt 3:
As per fuzzy-waffle's example, I have implemented the following, which doesn't appear to work correctly. Any ideas what I could be doing wrong?
ImageMatrix ImageMatrix::GetRotatedCopy(VDouble angle)
{
// Copy the specifications of the original.
ImageMatrix &source = *this;
ImageMatrix &target = CreateEmptyCopy();
double centerX = ((double)(source.GetColumnCount()-1)) / 2;
double centerY = ((double)(source.GetRowCount()-1)) / 2;
// Remember: row = y, column = x
for (VUInt32 y = 0; y < source.GetRowCount(); y++)
{
for (VUInt32 x = 0; x < source.GetColumnCount(); x++)
{
double dx = ((double)x) - centerX;
double dy = ((double)y) - centerY;
double newX = cos(angle) * dx - sin(angle) * dy + centerX;
double newY = cos(angle) * dy + sin(angle) * dx + centerY;
int ix = (int)round(newX);
int iy = (int)round(newY);
target[x][y][0] = source[ix][iy][0];
}
}
return target;
}
With this prototype matrix...
1 2 1
0 0 0
-1 -2 -1
... prototype.GetRotatedCopy(0) (which is correct) ...
1 2 1
0 0 0
-1 -2 -1
... prototype.GetRotatedCopy(90) (incorrect) ...
-2 0 0
-2 0 2
0 0 2
... prototype.GetRotatedCopy(180) (incorrect - but sort of logical?) ...
0 -1 -2
1 0 -1
2 1 0
... prototype.GetRotatedCopy(270) (incorrect - why is this the same as 0 rotation?) ...
1 2 1
0 0 0
-1 -2 -1
Solution:
As pointed out by Mark Ransom, I should be using radians, not degrees; I have adjusted my code as follows:
ImageMatrix ImageMatrix::GetRotatedCopy(VDouble degrees)
{
// Copy the specifications of the original.
ImageMatrix &source = *this;
ImageMatrix &target = CreateEmptyCopy();
// Convert degree measurement to radians.
double angle = degrees / 57.3;
// ... rest of code as in attempt #3 ...
Thanks for all your help guys!
1 2 1
0 0 0
-1 -2 -1
1 2 1
0 0 0
-1 -2 -1
-1 0 1
-2 0 2
-1 0 1
-1 -2 -1
0 0 0
1 2 1
1 0 -1
2 0 -2
1 0 -1
The algorithm, unless I read it wrong, seems to rotate around the point 0,0 which is not what you want. Maybe you need to add height/2 and width/2 to your row and column values before you plug them in.
for (int y = 0; y < 10; y++) {
for (int x = 0; x < 10; x++) {
VUInt32 newX = (cos(angle) * (x-5)) - (sin(angle) * (y-5));
VUInt32 newY = (sin(angle) * (x-5)) + (cos(angle) * (y-5));
target[newY][newX][0] = source[y][x][0];
}
}
This basically adjusts the rotation center from the upper left corner to the center of the image.
Here is a complete example I hacked up:
I think among other things you may have not been using radians (which we all should use and love). I keep the new coordinates in doubles which seemed to make it less finicky. Note that I am not doing bounds checking which I should but I was lazy.
If you need a faster rotation you can always use shearing like this example.
#include <math.h>
#include <stdio.h>
#define SIZEX 3
#define SIZEY 3
int source[SIZEX][SIZEY] = {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
int target[SIZEX][SIZEY];
int main () {
double angle = M_PI/2.0;
memset(target,0,sizeof(int)*SIZEX*SIZEY);
double centerX = ((double)(SIZEX-1))/2.0;
double centerY = ((double)(SIZEY-1))/2.0;
for (int y = 0; y < SIZEY; y++) {
for (int x = 0; x < SIZEX; x++) {
double dx = ((double)x)-centerX;
double dy = ((double)y)-centerY;
double newX = cos(angle)*dx-sin(angle)*dy+centerX;
double newY = cos(angle)*dy+sin(angle)*dx+centerY;
int ix = (int) round(newX);
int iy = (int) round(newY);
target[x][y] = source[ix][iy];
}
}
for (int i=0;i<SIZEY;i++) {
for (int j=0;j<SIZEX;j++) {
printf("%d ", target[j][i]);
}
printf("\n");
}
}
short answer: you're doing it wrong.
This is essentially a problem in interpolation, and the way you've approached it introduces discontinuities. Fundamentally this is because rotating a lattice (the regular grid your image is laid out on) does not result in another sampling on the same lattice except for very special cases.
There is no single correct way to do this, by the way, but there are various trade offs with respect to speed and accuracy and also what can be assumed about the original signal (image).
So what are your design parameters? Do you need this to be very fast or very accurate? How do you want to handle aliasing?
your formulas for newRow and newColumn are switched. Remember that row = y and column = x.
Rotation
The problem is that your memory accesses are out of bounds.
After rotation your NewRow and NewColumn may be larger than the original width/height of the image. They may even be negative. If you don't take care about that fact, you'll end up with garbage data (best case) or crashes.
The most common way to deal with this is to just ignore all such pixels. You could also clamp or wrap around the valid intervals. This get's a padding or tiling effect.
Here it's shown with ignoring outside pixels.
int width = 10;
int height = 10;
for (int row = 0; row < height; row++)
{
for (int column = 0; column < width; column++)
{
int newRow = (cos(angle) * row) - (sin(angle) * column);
int newColumn = (sin(angle) * row) + (cos(angle) * column);
if ((newRow >=0) && (newRow < width) &&
(newColumn >=0) && (newColumn < height))
{
target[row][column][0] = source[newRow][newColumn][0];
}
}
}