Related
I need to convert numbers between 0 and 1 billion to German words as a wstring.
I was pretty sure I got it right, but somewhere I have a mistake, and I don't see which.
For example for 1001, it should say "eintausendeins" ("onethousandone"), but instead it returns "nulleins" ("zero one").
Where am I going wrong?
wstring NumberToWords(wstring u)
{
map<int, wstring> numberWords =
{
{0, L"null"},
{1, L"eins"},
{2, L"zwei"},
{3, L"drei"},
{4, L"vier"},
{5, L"fünf"},
{6, L"sechs"},
{7, L"sieben"},
{8, L"acht"},
{9, L"neun"},
{10, L"zehn"},
{11, L"elf"},
{12, L"zwölf"},
{13, L"dreizehn"},
{14, L"vierzehn"},
{15, L"fünfzehn"},
{16, L"sechzehn"},
{17, L"siebzehn"},
{18, L"achtzehn"},
{19, L"neunzehn"},
{20, L"zwanzig"},
{30, L"dreißig"},
{40, L"vierzig"},
{50, L"fünfzig"},
{60, L"sechzig"},
{70, L"siebzig"},
{80, L"achtzig"},
{90, L"neunzig"},
{100, L"hundert"},
{1000, L"tausend"},
{1000000, L"million"},
{1000000000, L"milliarde"}
};
std::wstring result = L"";
std::wstring number = u;
if (number.empty() || number == L"0")
{
return numberWords[0];
}
std::vector<int> numberParts;
int size = number.size();
int start = size - 3;
int end = size;
while (start >= 0)
{
if (start == 0 && size % 3 != 0)
{
numberParts.push_back(stoi(number.substr(0, end - start)));
break;
}
numberParts.push_back(stoi(number.substr(start, end - start)));
end = start;
start -= 3;
}
for (int i = numberParts.size() - 1; i >= 0; i--)
{
int part = numberParts[i];
if (part >= 100) {
result += numberWords[part / 100];
result += L" ";
result += numberWords[100];
part = part % 100;
if (part > 0) {
result += L" ";
}
}
if (part >= 20)
{
result += numberWords[(part / 10) * 10];
part = part % 10;
if (part > 0) {
result += L" ";
result += numberWords[part];
}
}
else if (part > 0)
{
result += numberWords[part];
}
if (i > 0)
{
result += L" ";
if (part > 0)
{
result += numberWords[1000 * (int)pow(10, i)];
result += L"en";
}
}
}
return result;
}
This loop is incorrect
std::vector<int> numberParts;
int size = number.size();
int start = size - 3;
int end = size;
while (start >= 0)
{
if (start == 0 && size % 3 != 0)
{
numberParts.push_back(stoi(number.substr(0, end - start)));
break;
}
numberParts.push_back(stoi(number.substr(start, end - start)));
end = start;
start -= 3;
}
It should be something like
std::vector<int> numberParts;
int size = number.size();
int start = size - 3;
int end = size;
while (start > 3)
{
numberParts.push_back(stoi(number.substr(start, end - start)));
end = start;
start -= 3;
}
numberParts.push_back(stoi(number.substr(0, end - start)));
My version is completely untested code, but if you look at your version with number as "1001" you are only going round the initial loop once, consequently you only get one entry in numberParts.
Using a debugger would have shown you the problem very quickly, as would being able to 'run' the code accurately in your head (i.e. being able to see what the code you wrote actually does instead of what you hope it does). Both are essential skills for a programmer.
I have done this program to add two binary numbers of the same length stored in an integer array and store the sum in a new integer array. But due to some logical error, it does not show the desired output.
#include <conio.h>
#include <iostream.h>
void main() {
clrscr();
int a[] = {1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1,
1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1};
int b[] = {1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1,
1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0};
int temp[100];
int carry = 0, p = 35;
for(int i = 34; i >= 0; i--) {
if(a[i] + b[i] + carry == 0) {
temp[p] = 0;
carry = 0;
p--;
}
if((a[i] + b[i] + carry) == 1) {
temp[p] = 1;
carry = 0;
p--;
}
if((a[i] + b[i] + carry) == 2) {
temp[p] = 0;
carry = 1;
p--;
}
if((a[i] + b[i] + carry) > 2) {
temp[p] = 1;
carry = 1;
p--;
}
}
for(int pop = 0; pop < 36; pop++) cout << temp[pop];
getch();
}
the expected output is:
110100101001100101101010110101011111
actual output is:
101100110011011101011011101011011111
if((a[i] + b[i] + carry) == 2) {
temp[p] = 0;
carry = 1;
p--;
}
if((a[i] + b[i] + carry) > 2) {
temp[p] = 1;
carry = 1;
p--;
}
Go through this with a[i] = 1, b[i] = 1, carry = 0
This will trigger the first if here as it should, which then sets carry to 1.
Then the second if will find the configuration a[i] = 1, b[i] = 1, carry = 1 which triggers it despite the original configuration not fitting, causing the bug.
For the future, please get to know how to use a debugger, or at least how to include some debugging console prints in the program. Set stop points or prints where there would be nodes in a corresponding diagram to see if the flow takes the right route.
With prints:
for(int i = 34; i >= 0; i--) {
cout << "entered loop" << endl;
if(a[i] + b[i] + carry == 0) {
temp[p] = 0;
carry = 0;
p--;
cout << "recognized case 1" << endl;
}
if((a[i] + b[i] + carry) == 1) {
temp[p] = 1;
carry = 0;
p--;
cout << "recognized case 2" << endl;
}
if((a[i] + b[i] + carry) == 2) {
temp[p] = 0;
carry = 1;
p--;
cout << "recognized case 3" << endl;
}
if((a[i] + b[i] + carry) > 2) {
temp[p] = 1;
carry = 1;
p--;
cout << "recognized case 4" << endl;
}
}
(But using the debugger is better than prints.)
The issue in your code is you have a set of separate if statements which each modify carry, if carry is changed in such a way to alter the result of the subsequent if statements then multiple if statement bodies will be executed.
The simple fix is to change your last 3 ifs to else if.
You also need to add the final carry bit to your output:
temp[0] = carry;
for(int pop = 0; pop < 36; pop++) cout << temp[pop];
However your code could be greatly simplified using a swtich statement. Simpler code is generally less buggy and easier to understand:
for(int i = 34; i >= 0; i--, p--) {
switch(a[i] + b[i] + carry) {
case 0:
temp[p] = 0;
carry = 0;
break;
case 1:
temp[p] = 1;
carry = 0;
break;
case 2:
temp[p] = 0;
carry = 1;
break;
case 3:
temp[p] = 1;
carry = 1;
break;
default:
// should never be reached with inputs of 0 or 1
throw std::invalid_argument("invalid input");
}
}
This code could be simplified even further using bit manipulations to remove all branches and set the bits directly but I'll leave that as an exercise for the reader hint.
I've been trying all day creating different for loop combinations in c++ and I can't seem to get the right one.
I want my output to look like this:
Ribbon
How can you display this without using arrays?
EDIT: I tried like this but I can't replicate it on the opposite end. This has been so far the closest output I've got.
for(int i = 0; i < 6; i++)
{
cout<<"*";
for(int j = 5; j > i; j--)
{
cout<<" ";
}
for(int k = 0; k <= i; k++)
{
cout<<"*";
}
cout<<endl;
}
OUTPUT:
Fail ribbon
You have nine lines; let's number them 0 to 8. Line number n contains:
1 + (4 - abs(4 - n)) asterisks (1, 2, 3, 4, 5, 4, 3, 2, 1)
2 * abs (4 - n) spaces (8, 6, 4, 2, 0, 2, 4, 6, 8)
1 + (4 - abs(4 - n)) asterisks (1, 2, 3, 4, 5, 4, 3, 2, 1)
One option is to increment the number of stars on each row, then go back down once you reached the midpoint.
void printChar(char c, int count)
{
for (int i = 0; i < count; i++)
std::cout << c;
}
int main()
{
const int len = 10;
int stars = 0;
while (++stars <= len / 2)
{
int spaces = len - stars * 2;
printChar('*', stars);
printChar(' ', spaces);
printChar('*', stars);
std::cout << "\n";
}
stars--;
while (--stars > 0)
{
int spaces = len - stars * 2;
printChar('*', stars);
printChar(' ', spaces);
printChar('*', stars);
std::cout << "\n";
}
return 0;
}
I need to create a function that displays the following:
if number is between 0 - 5 then display values 1, 2, 3, 4, 5
if number is between 5 - 10 then display values 2, 4, 6, 8, 10
if number is between 10 - 50 then display values 10, 20, 30, 40, 50
if number is between 50 - 100 then display values 20, 40, 60, 80, 100
if number is between 100 - 500 then display values 100, 200, 300, 400, 500
if number is between 500 - 1000 then display values 200, 400, 600, 800, 1000
if number is between 1000 - 5000 then display values 1000, 2000, 3000, 4000, 5000
and so on...
I'm thinking of working with 2 arrays and then multiply with 10.
int *MyFunct(int number) {
int a[5] = { 1, 2, 3, 4, 5 };
int b[5] = { 2, 4, 6, 8, 10 };
if (number >= 0 && number <= 5) {
return a;
}
else if (number > 5 && number <= 10) {
return b;
}
else if (number > 10 && number <= 50) {
a[1] *= 10;
a[2] *= 10;
a[3] *= 10;
a[4] *= 10;
a[5] *= 10;
}
.
.
.
}
Is there any possibility to do this dynamically or simpler?
You can keep your first 2 arrays. You can do this in 3 steps.
Check if number is between 10^n and 5*(10^n). If it is, use the first array. If not, use the second array.
After that multiply each number by 10^n for some n such that 10^n < number.
This can be done by a for loop to check
I would start with something like that:
std::vector<unsigned int> MyFunct(unsigned int number) {
std::vector<unsigned int> numbers = { 1,2,3,4,5 };
unsigned int factor = 1;
while(number >= 10)
{
number /= 10;
factor *= 10;
}
if(number >= 5)
{
factor *= 2;
}
for(unsigned int i = 0; i < numbers.size(); ++i)
{
numbers[i] *= factor;
}
return numbers;
}
You could also work with logarithm of base 10.
You must first note that you cannot return an automatic array. For this use case, the simplest is to just use static ones.
Then your algorithm can be reworded as:
start with the array [1, 2, 3, 4, 5]
if the number is less than the last number of the array, return the array
else multiply the array alternatively by 2 and 5
In C++ it gives:
int *MyFunc(int n) {
static const int init[] = {1, 2, 3, 4, 5}; // the initial array
static int result[5];
int& max = result[4]; // alias for the last value
// copy init to result:
for (int i=0; i<5; i++) result[i] = init[i];
// find the range of n
for (;;) {
if (n <= max) {
break;
}
// multiply alternatively by 2 and by 5
for (int i=0; i<5; i++) result[i] *= 2;
if (n <= max) {
break;
}
for (int i=0; i<5; i++) result[i] *= 5;
}
return result;
}
Simple and compact...
Here's a variant that does what you say it should do – display those outputs – rather than return an array.
It does not use any arrays at all.
(Note that the problem as stated contains overlapping intervals. I have assumed that the intervals are actually 0-5, 6-10, 11-50, 51-100, 101-500, 501-1000, and >1000.)
int factor(int x)
{
if (x > 1000)
{
return 1000;
}
if (x > 500)
{
return 200;
}
if (x > 100)
{
return 100;
}
if (x > 50)
{
return 20;
}
if (x > 10)
{
return 10;
}
if (x > 5)
{
return 2;
}
return 1;
}
void display(int x)
{
auto f = factor(x);
for (int i = 1; i <= 5; ++i)
{
std::cout << f * i << " ";
}
std::cout << std::endl;
}
int main(int argc, char* argv[])
{
std::vector<int> test = { 1, 6, 11, 52, 103, 504, 1005 };
for (auto i: test)
{
display(i);
}
}
Output:
1 2 3 4 5
2 4 6 8 10
10 20 30 40 50
20 40 60 80 100
100 200 300 400 500
200 400 600 800 1000
1000 2000 3000 4000 5000
And a variation of factor that uses a table instead of a long chain of conditionals:
int factor(int x)
{
struct interval { int limit; int factor; };
interval intervals[] = {{1000, 1000},
{500, 200},
{100, 100},
{50, 20},
{10, 10},
{5, 2}};
for (auto i: intervals)
{
if (x > i.limit)
{
return i.factor;
}
}
return 1;
}
I made up my mind to write a little piece of code that gets two integers, lets say M and N ( M <= N ) and sum the digits of all the integers between them, inclusive. So for example if M = 1 and N = 9, DigitSum will equal to 45. If M = 10 and N = 11 the sum will be (1 + 0 (10) + 1 + 1 (11) = 3).
Here is my code so far (Done the for loop instead of the return):
#include <iostream>
#include <vector>
using namespace std;
// the partial digits sums digitSum[i] = the sum of the digits between 0 and i
int digitSum[] = {0, 1, 3, 6, 10, 15, 21, 28, 36, 45};
int pow_of_ten[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
// the sums of all the digits in the numbers from 1 to (10^(i) - 1) where i is the index in the array
long subsums[] = {0, 45, 20 * 45, 300 * 45, 4000 * 45, 50000 * 45, 600000 * 45, 7000000 * 45, 80000000 * 45,
900000000 * 45};
//Calculates the sum of all digits between 0 and M inclusive
long Digit_Sum(int M) {
if (M < 10) {
return digitSum[M];
}
long result = 0;
int same = M;
int counter = 0;
int lastdigit = 0;
while (same > 0) {
if (same < 10) {
lastdigit = same;
break;
}
same /= 10;
counter ++;
}
for(;counter >= 0; counter --) {
result += (subsums[counter] + M % pow_of_ten[counter] + 1) * lastdigit;
result += digitSum[lastdigit - 1] * pow_of_ten[counter];
if (counter == 0) {
break;
}
lastdigit = (M / pow_of_ten[counter - 1]) % 10;
}
return result;
}
int main() {
int M;
int N;
vector<long> sums;
while (true) {
cin >> M >> N;
if (M == 0 && N == 0) {
break;
}
sums.push_back(Digit_Sum(N) - Digit_Sum(M - 1));
}
for (vector<long>::iterator it = sums.begin(); it != sums.end(); ++it) {
cout << *it << endl;
}
}
For most cases this works well but an Online judge says it is wrong. I looked at other solutions that work but no one hard-coded the values in arrays the way I did. May this cause a partial problem, any ideas?
You can easily just create a for-loop to greatly simplify this code.
There is no need to go through all that effort.
for (Initialization Action, Boolean Expression, Update_Action)
Re deletion below: sorry, I have a bit influenza and mizread N as M. :(
I think a main error is M-1 in
sums.push_back(Digit_Sum(N) - Digit_Sum(M - 1));
Also noting that <when corrected that formula will only work for single-digit numbers. My comment earlier about using a simple formula was based on misunderstanding your problem description, in view of that formula and your examples. Both indicated single digit numbers only.
However, the complexity of the code appears unreasonably high. Consider this, assuming non-negative integers as input, and assuming m is always less than or equal to n:
#include <iostream>
#include <stdexcept>
using namespace std;
bool throwX() { throw std::runtime_error( "Ouch." ); }
auto main() -> int
{
for( ;; )
{
int m, n;
cin >> m >> n || throwX();
if( m == 0 && n == 0 ) { break; }
int sum = 0;
for( int i = m; i <= n; ++i )
{
for( int v = i; v != 0; v /= 10 )
{
sum += v % 10;
}
}
cout << sum << endl;
}
}
It needs not be more complicated than that.
Tested and working to spec, sans console input:
#include <iostream>
#include <string>
using namespace std;
void sum_a_to_b(const int & a, const int & b)
{
if (a <= b && a >= 0)
{
long long sum = 0;
for (int i = a; i <= b; i++)
{
sum += i;
}
cout << "Sum of digits from " << a << " through " << b << " is " << sum << ".\n";
}
}
int main()
{
sum_a_to_b(5, 6);
sum_a_to_b(1, 9);
}