Am I using this switch case incorrectly? - c++

So the idea of this program is to get the users input in the form of a Roman Numeral up to 4999. I decided to use a switch case to loop through an string of input. The problem is when I put in a value like 99 which would be XCIX it returns -101. Any help is grateful.
int number = 0, M = 1000, D = 500, C = 100, L = 50, X = 10, V = 5, I = 1;
for (int i = 0; i < roman.length(); i++)
{
switch (roman[i])
{
case 'M': number += 1000; break;
case 'D': if (roman[i + 1] != 'D' && i + 1 < roman.size())
number -= 500;
else
number += 500;
break;
case 'C': if (roman[i + 1] != 'C' && i + 1 < roman.size())
number -= 100;
else
number += 100;
break;
case 'L': if (roman[i + 1] != 'L' && i + 1 < roman.size())
number -= 50;
else
number += 50;
break;
case 'X': if (roman[i + 1] != 'X' && i + 1 < roman.size())
number -= 10;
else
number += 10;
break;
case 'V': if (roman[i + 1] != 'V' && i + 1 < roman.size())
number -= 5;
else
number += 5;
break;
case 'I':
if (roman[i + 1] != 'I' && i + 1 < roman.size())
number -= 1;
else
number += 1;
break;
}
}
return number;

Roman numerals count negative only when they appear before a digit with higher value. Being different is not enough.

Related

Stack smashing detected

#include <iostream>
using namespace std;
int main()
{
int tablica[9];
string inputromanum;
cout << "ROMAN: ";
cin >> inputromanum;
int maxindeks;
bool disablenextcomp = false;
int readysolution = 0;
maxindeks = inputromanum.length() - 1;{}{}
for (int i = 0; i <= maxindeks; i++)
{
if (inputromanum[i] == 'M' || inputromanum[i] == 'm')
{
tablica[i] = 1000;
}
if (inputromanum[i] == 'D' || inputromanum[i] == 'd')
{
tablica[i] = 500;
}
if (inputromanum[i] == 'C'|| inputromanum[i] == 'c')
{
tablica[i] = 100;
}
if (inputromanum[i] == 'L' || inputromanum[i] == 'l')
{
tablica[i] = 50;
}
if (inputromanum[i] == 'X' || inputromanum[i] == 'x')
{
tablica[i] = 10;
}
if (inputromanum[i] == 'V' || inputromanum[i] == 'v')
{
tablica[i] = 5;
}
if (inputromanum[i] == 'I' || inputromanum[i] == 'i')
{
tablica[i] = 1;
}
}
cout<<endl;
for(int i4 = 0; i4 <= maxindeks; i4++)
{
cout<<"tablica["<<i4<<"] = "<<tablica[i4]<<endl;
}
for (int i2 = 0; i2 <= maxindeks; i2++)
{
int i5 = i2 + 1;
if (i5 <= maxindeks)
{
//cout<<endl<<"tablica[i2 + 1] = "<<tablica[i2 + 1];
//cout<<endl<<"tablica[i2] = "<<tablica[i2];
//cout<<endl<<"tablica[i2 + 1] - tablica[i2] = "<<tablica[i2 + 1] - tablica[i2];
if (tablica[i2 + 1] - tablica[i2] > 0 && disablenextcomp == false)
{
//cout<<endl<<"readysolution + (tablica[i2 + 1] - tablica[i2]) = "<<readysolution + (tablica[i2 + 1] - tablica[i2])<<endl;
readysolution = readysolution + (tablica[i2 + 1] - tablica[i2]);
disablenextcomp = true;
}
else
{
if(disablenextcomp == false)
{
//cout<<endl<<"readysolution + tablica[i2] = "<<readysolution + tablica[i2]<<endl;
readysolution = readysolution + tablica[i2];
}
else
{
disablenextcomp = false;
}
}
}
else
{
if(disablenextcomp == false)
{
//cout<<endl<<endl<<"OSTATNI INDEKS";
//cout<<endl<<"tablica[i2] = "<<tablica[i2];
//cout<<endl<<"readysolution + tablica[i2] = "<<readysolution + tablica[i2];
readysolution = readysolution + tablica[i2];
}
}
i5++;
}
cout << endl << readysolution;
}
This is my program. made for decoding roman numerals into arabic ones. It works as intended in most cases, however, one of my colleagues found it to produce this error while inputting MMMCMXCVIII into the program:
*** stack smashing detected ***: terminated
It would refuse to work afterwards.
I wasn't able to find different numbers that would cause this error except MMMMMMMMMMM.
It seems to fail when the index of tablica array exceeds 10. I don't know why it does so, as i am a novice in c++. It should've outputted 3999 instead of the error appearing. The numbers it should process successfully should range from 1 to 5000.
Thanks to folks in the comments, I've found the cause.
The tablica[9] array is supposed to store 9 or less characters.
The length of the input (MMMCMXCVIII in this case) has more characters, therefore it makes the for loop responsible for storing values for each character to cause mentioned above error, as there are no remaining units to store the values in.
I've expanded the storage of tablica to 25 characters.
In modern C++ it is considered bad practice to use C-style arrays and index loops whenever you can avoid this. So, fo example you can rewrite first loop like this:
std::vector<int> tablica;
tablica.reserve(inputromanum.size()); // This line is not necessary, but it can help optimize memory allocations
for (char c : inputromanum)
{
if (c == 'M' || c == 'm')
{
tablica.push_back(1000);
}
if (c == 'D' || c == 'd')
{
tablica.push_back(500);
}
if (c == 'C'|| c == 'c')
{
tablica.push_back(100);
}
if (c == 'L' || c == 'l')
{
tablica.push_back(50);
}
if (c == 'X' || c == 'x')
{
tablica.push_back(10);
}
if (c == 'V' || c == 'v')
{
tablica.push_back(5);
}
if (c == 'I' || c == 'i')
{
tablica.push_back(1);
}
}
And you will avoid your issue completly. Something similar can be done with other loops too. This approach also has benefit of (somewhat) properly handling situations when input line has other symbols, which is not roman number. Try it on your version and you will see what I mean.
One more point. When you need to do something different depending of value of one variable, like you did with all those ifs. There is special statement in C/C++ for this: switch. So instead of those ifs you can do this:
std::vector<int> tablica;
tablica.reserve(inputromanum.size()); // This line is not necessary, but it can help optimize memory allocations
for (char c : inputromanum)
{
switch(c)
{
case 'M':
case 'm':
tablica.push_back(1000);
break;
case 'D':
case 'd':
tablica.push_back(500);
break;
case 'C':
case 'c':
tablica.push_back(100);
break;
case 'L':
case 'l':
tablica.push_back(50);
break;
case 'X':
case 'x':
tablica.push_back(10);
break;
case 'V':
case 'v':
tablica.push_back(5);
break;
case 'I':
case 'i':
tablica.push_back(1);
break;
}
}

What is the correct way to transform the formula for the determination of the day of the week into C++?

I have an assignment where I need to figure out which day of the week a date was/is. The formula on Wikipedia goes as following
where
d = day (1-31)
m = month (starting with March = 1 up to February=12)
y = last 2 digits of a year
c = first 2 digits of a year
(y and c must be reduced by 1 if the month is January or February)
My function goes as follows:
int wochentagWiki(int inttag, int intmonat, int intjahr) {
int d = inttag;
int m = 0;
switch (intmonat) {
case 1:
m = 11;
break;
case 2:
m = 12;
break;
case 3:
m = 1;
break;
case 4:
m = 2;
break;
case 5:
m = 3;
break;
case 6:
m = 4;
break;
case 7:
m = 5;
break;
case 8:
m = 6;
break;
case 9:
m = 7;
break;
case 10:
m = 8;
break;
case 11:
m = 9;
break;
case 12:
m = 10;
break;
}
int y = intjahr % 100;
if (intmonat == 1 || intmonat == 2) {
y--;
}
int c = intjahr / 100;
if (intmonat == 1 || intmonat == 2) {
c--;
}
int w = (d + (2.6 * m - 0.2) + y + (y / 4) + (c / 4) - (__int64)2 * c) % 7;
return w;
}
My problem is that w always returns a wrong value, and I think it's because I translated the formula the wrong way. What would be the correct way to write it down?
It looks to me like you've made a mistake in copying down the formula:
(y and c must be reduced by 1 if the month is January or February)
But Wikipedia says:
Y is the year minus 1 for January or February, and the year for any other month
y is the last 2 digits of Y
c is the first 2 digits of Y

Turn if else into a for loop

I want to choose positions 1, 3, 7, 9.
I made an if else statement that solves the problem. Could this be implemented in a for loop.
int move1 = (rand() % 4) + 1;
if (move1 == 1)
{
move1 = 1;
}
else if (move1 == 2)
{
move1 = 3;
}
else if (move1 == 3)
{
move1 = 7;
}
else if (move1 == 4)
{
move1 = 9;
}
I don't know about a loop, but usually you want to implement these kind of things with a switch statement. Something like this:
int move1;
switch(rand() % 4)
{
case 1:
move1 = 1;
break;
case 2:
move1 = 3;
break;
case 3:
move1 = 7;
break;
case 4:
move1 = 9;
break;
}

finding the first set bit in a binary number [duplicate]

This question already has answers here:
Efficient bitwise operations for counting bits or find the right|left most ones
(6 answers)
Position of least significant bit that is set
(23 answers)
Closed 9 years ago.
I need to find the first set bit in a binary number from right to left; I came up with this solution:
int cnt=0;
while (number& 1 ==0)
{
cnt++;
number>>=1;
}
Is there a better way of doing it? Some clever bit manipulation technique?
processor may have instruction to find that directly:
Windows/MSVC:
_BitScanForward()
_BitScanReverse()
GCC:
__builtin_ffs()
__builtin_ctz()
__builtin_clz()
These typically map directly to native hardware instructions. So it doesn't get much faster than these.
But since there's no C/C++ functionality for them, they're only accessible via compiler intrinsics.
You can do it manually that way:
n & (n - 1) is a technique to remove the rightmost set bit.
So, n - (n & n - 1) will return a number with only the rightmost set bit.
then a 'log2' of the result give the solution: this link may help
You may alternatively use a switch case with all 1 << k will give you the solution
switch (n - (n & n - 1)) {
case 0: ...
case 1 << 0: return 0;
case 1 << 1: return 1;
...
}
If you want it to be fast, bitscan instruction (bsf, bsr) or bit-twiddling hack is the target to go.
EDIT:
The idea of using switch-case table to improve performance is nothing but immature.
Bit Twiddling Hacks offers an excellent collection of, er, bit twiddling hacks, with performance/optimisation discussion attached. For your problem (from that site), you can use multiply-and-lookup strategy:
unsigned int c = number; // your input number
int r; // result goes here
static const int MultiplyDeBruijnBitPosition[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r = MultiplyDeBruijnBitPosition[((uint32_t)((c & -c) * 0x077CB531U)) >> 27];
Your code
int cnt=0;
while (number& 1 ==0)
{
cnt++;
number>>=1;
}
has a bug. For example if number is equal to 0 then the loop will be infinite.
I would rewrite it the following way
int cnt = 0;
if ( number ) while ( !( number & ( 1 << cnt++ ) ) );
In this case if number is not equal to 0 then the position (cnt) of the set bit will be count starting from 1. Otherwise the position will be equal to 0.
I'm not sure the accepted answer is right. I just tested the naive loop versus the (num & -num) solution. They are both the same speed. The naive loop is much less code. I built with:
gcc 4.7.2 from MinGW, on Win 7
gcc test.c -o test.exe -std=c99 -Wall -O2
Here's my code (it probably has some corner case bugs, but I suspect the timings are roughly valid).
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM_NUMS 65536
int find_first_bits(unsigned nums[NUM_NUMS])
{
int total = 0; // Prevent compiler from optimizing out the code
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < NUM_NUMS; i++) {
switch (nums[i] & -nums[i]) {
case (1<<0): total += 1; break;
case (1<<1): total += 2; break;
case (1<<2): total += 3; break;
case (1<<3): total += 4; break;
case (1<<4): total += 5; break;
case (1<<5): total += 6; break;
case (1<<6): total += 7; break;
case (1<<7): total += 8; break;
case (1<<8): total += 9; break;
case (1<<9): total += 10; break;
case (1<<10): total += 11; break;
case (1<<11): total += 12; break;
case (1<<12): total += 13; break;
case (1<<13): total += 14; break;
case (1<<14): total += 15; break;
case (1<<15): total += 16; break;
case (1<<16): total += 17; break;
case (1<<17): total += 18; break;
case (1<<18): total += 19; break;
case (1<<19): total += 20; break;
case (1<<20): total += 21; break;
case (1<<21): total += 22; break;
case (1<<22): total += 23; break;
case (1<<23): total += 24; break;
case (1<<24): total += 25; break;
case (1<<25): total += 26; break;
case (1<<26): total += 27; break;
case (1<<27): total += 28; break;
case (1<<28): total += 29; break;
case (1<<29): total += 30; break;
case (1<<30): total += 31; break;
case (1<<31): total += 32; break;
}
}
}
return total;
}
int find_first_bits2(unsigned nums[NUM_NUMS])
{
int total = 0; // Prevent compiler from optimizing out the code
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < NUM_NUMS; i++) {
unsigned mask = 1;
for (int cnt = 1; cnt <= 32; cnt++, mask <<= 1) {
if (nums[i] & mask) {
total += cnt;
break;
}
}
}
}
return total;
}
int main() {
// Create some random data to test
unsigned nums[NUM_NUMS];
for (int i = 0; i < NUM_NUMS; i++) {
nums[i] = rand() + (rand() << 15);
}
clock_t start_time, end_time;
int result;
start_time = clock();
result = find_first_bits(nums);
end_time = clock();
printf("Time = %.5f, result = %d\n", (end_time - start_time) / (double)(CLOCKS_PER_SEC), result);
start_time = clock();
result = find_first_bits2(nums);
end_time = clock();
printf("Time = %.5f, result = %d\n", (end_time - start_time) / (double)(CLOCKS_PER_SEC), result);
}

Optimisation hint for array of random numbers

To provide context, I'm working through Programming Praxis Bingo Challenge and wanted to see how fast I could make this code run.
static void fisher_yates(T& source) {
const size_t len = source.size();
for(size_t i = 1; i < len;++i) {
std::swap(source[i],source[rand() % (i+1)]);
}
}
std::array<int,25> generate_table() {
std::array<int,25> bingo_grid;
for(int i = 0 ; i < 25;++i) {
switch(i) {
case 0: case 1: case 2: case 3: case 4:
bingo_grid[i] = rand() % 15 + 1;
break;
case 5: case 6: case 7: case 8: case 9:
bingo_grid[i] = rand() % 15 + 16;
break;
case 10: case 11: case 12: case 13: case 14:
bingo_grid[i] = rand() % 15 + 31;
break;
case 15: case 16: case 17: case 18: case 19:
bingo_grid[i] = rand() % 15 + 46;
break;
case 20: case 21: case 22: case 23: case 24:
bingo_grid[i] = rand() % 15 + 61;
break;
}
}
bingo_grid[12] = 0;
return bingo_grid;
}
bool is_bingoed(const std::array<int,25>& grid) {
// Check columns
if(grid[0] == 0) {
if(grid[1] == 0 && grid[2] == 0 && grid[3] == 0 && grid[4] == 0)
return true;
if(grid[0] == 0 && grid[6] == 0 && grid[18] == 0 && grid[24] == 0)
return true;
if(grid[5] == 0 && grid[10] == 0 && grid[15] == 0 && grid[20] == 0)
return true;
}
if(grid[1] == 0) {
if(grid[6] == 0 && grid[11] == 0 && grid[16] == 0 && grid[21] == 0)
return true;
}
if(grid[2] == 0) {
if(grid[7] == 0 && grid[17] == 0 && grid[22] == 0)
return true;
}
if(grid[3] == 0) {
if(grid[8] == 0 && grid[13] == 0 && grid[18] == 0 && grid[23] == 0)
return true;
}
if(grid[4] == 0) {
if(grid[9] == 0 && grid[14] == 0 && grid[19] == 0 && grid[24] == 0)
return true;
if(grid[8] == 0 && grid[16] == 0 && grid[21] == 0)
return true;
}
if(grid[6] == 0) {
if(grid[6] == 0 && grid[7] == 0 && grid[8] == 0 && grid[9] == 0)
return true;
}
if(grid[12] == 0) {
if(grid[10] == 0 && grid[11] == 0 && grid[13] == 0 && grid[14] == 0)
return true;
}
if(grid[18] == 0) {
if(grid[15] == 0 && grid[16] == 0 && grid[17] == 0 && grid[19] == 0)
return true;
}
return false;
}
static bool mark_card(const int card,std::array<int,25>& bingo_grid) {
for(auto &i : bingo_grid)
if(card == i) {
i = 0;
return true;
}
return false;
}
int play_game() {
// Bingo is 5 columns, each column(n) is random permutation of 1-15*n
// Fisher-Yates to generate random permutations
// Create 500 playing cards
const int max = 500;
std::vector<std::array<int,25>> bingo_cards;
bingo_cards.reserve(max);
for(int i = 0; i<max;++i) {
bingo_cards.push_back(generate_table());
//display_bingo(bingo_cards[i]);
}
// Random shuffle 75 cards
auto iter = boost::counting_range(1,76);
std::vector<int> cards(std::begin(iter),std::end(iter));
fisher_yates(cards);
bool is_finished = false;
int counter = 0;
for(auto card : cards) {
for(auto& playing_card : bingo_cards) {
if(mark_card(card,playing_card)) {
//display_bingo(playing_card);
if(is_bingoed(playing_card))
return counter;
}
}
counter++;
}
return counter;
}
int bingo() {
srand(time(NULL));
int total = 0;
for(int i = 0 ; i < 10000;i++) {
total+=play_game();
}
boost::singleton_pool<boost::pool_allocator_tag, sizeof(int)>::release_memory();
return total / 10000;
}
The original version used a boost::multi_array to represent the grid. After profiling, I changed it to a std::array which got me a significant speed up. I then moved from using fisher_yates shuffle to generate bingo cards to using a random number generator.
Then finally I changed the is_bingoed test function to reduce the number of checks per call to speed up the game-over check.
All this has helped. Right now if I profile this code, the generate_table function takes up 72% of the time, mark_card() is 18%, and is_bingoed() about 6%. I'm looking for hints to see what can be done to improve the speed of either.
My first thought with is_bingoed() is to use the SSE intrinsics to do a compare with 0 (maybe use XOR?) but I don't have any ideas on the generate_table() or mark_car(). This is more of a self challenge for fun but wondered what others thought?
Current timing is it takes 4.6s on a 2Ghz Q6660 (down from 35s originally)
Just focussing on your most expensive function, generate_table, you can simplify this part of the code and make it less branchy, which may help:
for(int i = 0 ; i < 25;++i) {
switch(i) {
case 0: case 1: case 2: case 3: case 4:
bingo_grid[i] = rand() % 15 + 1;
break;
case 5: case 6: case 7: case 8: case 9:
bingo_grid[i] = rand() % 15 + 16;
break;
case 10: case 11: case 12: case 13: case 14:
bingo_grid[i] = rand() % 15 + 31;
break;
case 15: case 16: case 17: case 18: case 19:
bingo_grid[i] = rand() % 15 + 46;
break;
case 20: case 21: case 22: case 23: case 24:
bingo_grid[i] = rand() % 15 + 61;
break;
}
}
e.g.
for(int i = 0 ; i < 25;++i) {
int r = rand() % 15 + 1;
bingo_grid[i] = r + (i / 5) * 15;
}
Beyond that I'd look at a faster rand() and also see if you can get rid of the divide and and modulo.
On a separate note, your algorithm may be flawed in that there is nothing to prevent duplicate numbers in bingo_grid.
Changing the is_bingoed() method to use SSE instructions (using Agner Fog's library) and Paul R's generate_table() reduced the time to just 1.05s. And using Intel's fast_rand() function got it down to 0.38s.
So I thought I'd paste the code changes for others who might be interested.
static unsigned int g_seed;
//Used to seed the generator.
inline void fast_srand( int seed )
{
g_seed = seed;
}
//fastrand routine returns one integer, similar output value range as C lib.
inline int fastrand()
{
g_seed = (214013*g_seed+2531011);
return (g_seed>>16)&0x7FFF;
}
bool is_bingoed(const std::array<int,25>& grid) {
// Check columns
Vec8i vec(grid[0],grid[1],grid[2],grid[3],grid[4],0,0,0);
Vec4i vec2(grid[6],grid[18],grid[24],0);
Vec4i vec3(grid[5],grid[10],grid[15],20);
Vec8i vec4(grid[1],grid[6],grid[11],grid[16],grid[21],0,0,0);
Vec4i vec5(grid[2],grid[7],grid[17],grid[22]);
Vec8i vec6(grid[3],grid[8],grid[13],grid[18],grid[23],0,0,0);
Vec8i vec7(grid[4],grid[9],grid[14],grid[19],grid[24],0,0,0);
Vec4i vec8(grid[8],grid[16],grid[21],grid[4]);
Vec4i vec9(grid[6],grid[7],grid[8],grid[9]);
Vec8i vec10(grid[12],grid[10],grid[11],grid[13],grid[14],0,0,0);
Vec8i vec11(grid[18],grid[15],grid[16],grid[17],grid[19],0,0,0);
if(horizontal_and(vec) && horizontal_and(vec2) && horizontal_and(vec3) && horizontal_and(vec4) &&
horizontal_and(vec5) && horizontal_and(vec6) && horizontal_and(vec7) && horizontal_and(vec8)) {
return false;
}
if(horizontal_and(vec9) && horizontal_and(vec10) && horizontal_and(vec11)) {
return false;
}
return true;
}