Convert octal representation of a number to decimal - c++

Assume one has an vector or array of N elements (N can be very large) containing the octal representation of a non negative integer. How do I get the decimal representation of the number from this array? The code has to be really fast.
EDIT: array A of N elements contains octal representation of a non-negative integer K, i.e. each element of A belongs to the interval [0; 7] (both ends included)
Example: A[0] = 2; A[1] = 6; A[2] = 3
Now a naive calculation would be 2*8pow0 + 6*8pow1 + 3*8pow2 = 2+ 48+ 192 = 242
I tried this but it does not seem to work for large inputs > 6K
//vector<int> A is the input
using namespace std;
vector<int>::iterator it = A.begin();
unsigned int k = 0;
unsigned int x = 0;
while(it < A.end()){
x = x | (*it<<3*k);
k++;
it++;
}
I am also having problems converting a hexadecimal string to its decimal representation? Is this the correct way to do this in C++:
//Assume S to be your input string containing a hex representation
//like F23
std::stringstream ss;
ss << std::hex << S;
ss >> x;

Arbitray precision octal to decimal conversion is rather annoying because there is no way to localize the computation. In other words a change in the most significant digit of the octal number will change even the least significant digit in the decimal representation.
That said I think I would convert the octal number to a say base-1000000000 number and then I'd print that (this is instead a trivial problem, each base-1000000000 digit just maps trivially to 9 base-10 digits).
The conversion to base-1000000000 is simple because you only need to support incrementing and multiplying by two (just consider the input as binary with three bits for each octal digit).
EDIT
I tried to implement it in C++ and this is the resulting code
#include <stdio.h>
#include <vector>
int main(int argc, const char *argv[]) {
// Base 100,000,000 accumulator
// Initialized with one digit = 0
std::vector<unsigned> big(1);
const unsigned DIGIT = 100000000;
for (int c=getchar(); c >= '0' && c <= '7'; c=getchar()) {
// Multiply accumulator by 8 and add in incoming digit
int carry = c - '0';
for (int i=0,n=big.size(); i<n; i++) {
unsigned x = big[i] * 8 + carry;
carry = x / DIGIT;
big[i] = x - carry * DIGIT;
}
if (carry) big.push_back(carry);
}
// Output result in decimal
printf("%i", big.back());
for (int i=int(big.size())-2; i>=0; i--) {
printf("%08i", big[i]);
}
putchar('\n');
return 0;
}
On my PC the time to convert an 80,000 digit octal number to decimal (resulting in 72246 digits) is about 1.2 seconds. Doing the same using python eval/str the time is about 3 seconds. The number used was "01234567" * 10000.
The code above uses 100,000,000 as base so that it can process one digit (3 bits) at a time with 32-bit arithmetic not overflowing with the intermediate results. I tried also using 64 bit integers or the 53 bit integer part of a double but the code was running always slower than in this case (one reason is probably the division in the inner loop that can be converted to a multiplication in the 32 bit case).
This is still a simple O(n^2) implementation that would take ages to convert a 10,000,000-digits octal number.

This is what I came up with:
template<typename Iter>
int read_octal(Iter begin, Iter end)
{
int x = 0;
int f = 1;
for (; begin != end; ++begin)
{
x += *begin * f;
f *= 8;
}
return x;
}
int main()
{
int test[] = {2, 6, 3};
int result = read_octal(test + 0, test + 3);
std::cout << result << '\n';
}
I tried this but it does not seem to work for large inputs > 6K
What exactly do you mean by 6k? An int usually has 32 bits, and an octal digit has 3 bits. Thus, you cannot have more than 10 elements in your range, otherwise x will overflow.
I am also having problems converting a hexadecimal string to its decimal representation?
Well, you could always write a function to parse a string in hex format yourself:
int parse_hex(const char* p)
{
int x = 0;
for (; *p; ++p)
{
x = x * 16 + digit_value(*p);
}
return x;
}
With the most portable version of digit_value being:
int digit_value(char c)
{
switch (c)
{
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'A':
case 'a': return 10;
case 'B':
case 'b': return 11;
case 'C':
case 'c': return 12;
case 'D':
case 'd': return 13;
case 'E':
case 'e': return 14;
case 'F':
case 'f': return 15;
}
}

Related

how to print multiple numbers to words

in my code, i don't understand why zero doesn't print i did all possible solutions that I know but it doesn't print zero.
#include <iostream>
using namespace std;
int main(){
int digits;
int numberOne = 0;
int integer;
cout<<"Enter the number: ";
cin>>digits;
while (digits != 0) {
numberOne = (numberOne * 10) + (digits % 10);
digits /= 10;
}
for (integer = numberOne; integer > 0; integer = integer / 10){
switch (integer % 10) {
case 0:
cout<<"Zero\n";
break;
case 1:
cout<<"One\n";
break;
case 2:
cout<<"Two\n";
break;
case 3:
cout<<"Three\n";
break;
case 4:
cout<<"Four\n";
break;
case 5:
cout<<"Five\n";
break;
case 6:
cout<<"Six\n";
break;
case 7:
cout<<"Seven\n";
break;
case 8:
cout<<"Eight\n";
break;
case 9:
cout<<"Nine\n";
break;
}
}
return 0;
}
zero doesn't print how do I fix it?
Expected output is 900 (nine zero zero) but zero doesn't print in my case. help thanks.
Because in this line:
for (integer = numberOne; integer > 0; integer = integer / 10){
the loop continues only if integer>0. Therefore you never see "Zero".
Why doesn't it print zero? Look at your loop
for (integer = numberOne; integer > 0; integer = integer / 10){
If integer equals zero then the loop is never entered. You need to be a bit smarter in your loop. How about counting digits?
int num_digits = 0;
while (digits != 0) {
numberOne = (numberOne * 10) + (digits % 10);
digits /= 10;
++num_digits;
}
Now that you have the number of digits, you can use that in your second loop
for (integer = numberOne; num_digits > 0; integer = integer / 10, --num_digits) {
...
}
You still need to treat zero as a special case, because if the user enters 0 then num_digits will equal zero and you again won't print anything. I'll leave you to figure out how to fix that.
#include <iostream>
using namespace std;
int main(){
int digits;
int arrayLength = 10;
cout<<"Enter the number: ";
cin>>digits;
string reverse_number[arrayLength]; //array to store the string of numbers like "Zero"
int array_counter=0;
while (digits != 0) {
switch (digits % 10) {
case 0:
reverse_number[array_counter++] = "Zero";
break;
case 1:
reverse_number[array_counter++] = "One";
break;
case 2:
reverse_number[array_counter++] = "Two";
break;
case 3:
reverse_number[array_counter++] = "Three";
break;
case 4:
reverse_number[array_counter++] = "Four";
break;
case 5:
reverse_number[array_counter++] = "Five";
break;
case 6:
reverse_number[array_counter++] = "Six";
break;
case 7:
reverse_number[array_counter++] = "Seven";
break;
case 8:
reverse_number[array_counter++] = "Eight";
break;
case 9:
reverse_number[array_counter++] = "Nine";
break;
}
digits /=10;
}
int num_digits = array_counter;
for (int i = 0; i < num_digits; i++) {
cout << reverse_number[--array_counter] <<" ";
}
return 0;
}
The reason why your zeros are not showing while doing for 900 is because when you are reversing 900 to 009, there is no condition mentioned to handle the leading zeros in 009 which are just ignored. For this the best approach would be to store them somewhere else like in a string or an array. You can also just store the number words directly to an array while you are converting, that way you wont lose the leading zeros.
The other answers have already addressed the main problem with your code.This answer focus on the post's title: how to print multiple numbers to words?
First, I would consider using an array of strings instead of a switch.
In order to retrieve a string for a given digit, you would just index that array.(see digits[c - '0'] below)
Also, if you are allowed to convert a number to a string, the code would reduce to walking that string and converting each character to a word.You could read the number directly as a string from the standard input, or use std::to_string on an integer.
Notice also that, when reading a character c from the a string of digits, c - '0' gives you an integer betweeen 0 and 9, which you can use as the array index.
Demo
#include <array>
#include <iostream>
#include <string> // to_string
std::array<std::string, 10> digits{
"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"
};
void digits_to_words(int n) {
for (unsigned char c : std::to_string(n)) {
std::cout << digits[c - '0'] << "\n";
}
}
int main() {
for (int n : { 0, 5, 105, 900 }) {
std::cout << "Number: " << n << "\n";
digits_to_words(n);
std::cout << "\n";
}
}

Roman Numerals to Arabic (vinculum) - reading characters in a string

I am currently working on a project that converts Roman Numerals to Arabic Numbers and vice versa.
I am also responsible to implement concepts like vinculum, where if you put a bar on top of a Roman numeral, the numbers below will be multiplied by 1,000.
The problem I am having is I can get only one side working, meaning:
I can either just convert from Roman Numeral to Arabic without Vinculum:
ex. I = 1, II = 2
However, when this works my vinculum code does not work.
Here is a snippet of my code:
int romanToDecimal(char input[], size_t end) {
int roman = 0;
int vroman = 0;
for (int i = 0; i < strlen(input); ++i)
{
int s1 = value(input[i]);
int s2 = value(input[i]);
if (input[i] == '-')
{
for (int j = i - 1; j >= 0; --j)
{
roman = (roman + value(input[j]));
}
roman *= 1000;
for (int k = i + 1; k <= strlen(input); k++)
roman += value(input[k]);
}
else
roman += s1;
}
return roman;
}
We use '-' instead of the bar on top of the characters, because we cannot do that in computer easily. So IV-, would be 4000 and XI- would be 11,000 etc...
I understand that the way I am doing the loop is causing some numbers that were converted to add twice, because if(input[i] == '-') cycles through each character in the string one at a time.
OK, so my question is basically what is the logic to get it to work? So if the string contains '-' it will multiply the number by 1000, if the string does not contain '-' at ALL, then it will just convert as normal. Right now I believe what is happening is that when "if (input[i] == '-')" is false, that part of the code still runs, how do I not get it to run at all when the string contains '-'??
The posted code seems incomplete or at least has some unused (like end, which if it represents the length of string could be used in place of the following repeated strlen(input)) or meaningless (like s2) variables.
I can't understand the logic behind your "Vinculum" implementation, but the simple
roman += s1; // Where s1 = value(input[i]);
It's clearly not enough to parse a roman number, where the relative position of each symbol is important. Consider e.g. "IV", which is 4 (= 5 - 1), vs. "VI", which is 6 (= 5 + 1).
To parse the "subtractive" notation, you could store a partial result and compare the current digit to the previous one. Something like the following:
#include <stdio.h>
#include <string.h>
int value_of(char ch);
long decimal_from_roman(char const *str, size_t length)
{
long number = 0, partial = 0;
int value = 0, last_value = 0;
for (size_t i = 0; i < length; ++i)
{
if (str[i] == '-')
{
number += partial;
number *= 1000;
partial = 0;
continue;
}
last_value = value;
value = value_of(str[i]);
if (value == 0)
{
fprintf(stderr, "Wrong format.\n");
return 0;
}
if (value > last_value)
{
partial = value - partial;
}
else if (value < last_value)
{
number += partial;
partial = value;
}
else
{
partial += value;
}
}
return number + partial;
}
int main(void)
{
char const *tests[] = {
"I", "L", "XXX", "VI", "IV", "XIV", "XXIII-",
"MCM", "MCMXII", "CCXLVI", "DCCLXXXIX", "MMCDXXI", // 1900, 1912, 246, 789, 2421
"CLX", "CCVII", "MIX", "MLXVI" // 160, 207, 1009, 1066
};
int n_samples = sizeof(tests) / sizeof(*tests);
for (int i = 0; i < n_samples; ++i)
{
long number = decimal_from_roman(tests[i], strlen(tests[i]));
printf("%12ld %s\n", number, tests[i]);
}
return 0;
}
int value_of(char ch)
{
switch (ch)
{
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
default:
return 0;
}
}
Note that the previous code only checks for wrong characters, but doesn't discard strings like "MMMMMMMMMMIIIIIIIIIIIIIV". Consider it just a starting point and feel free to improve it.

Codekata to convert number from hex to dec integer representation

I am writing a small program convert hex representation of a string , it is a kata to improve my skills.
This is what I have come up with
std::vector<int> decimal( std::string const & s )
{
auto getint = [](char const k){
switch(k){
case 'f':
return 15;
case 'e':
return 14;
case 'd':
return 13;
case 'c':
return 12;
case 'b':
return 11;
case 'a':
return 10;
case '9':
return 9;
case '8':
return 8;
case '7':
return 7;
case '6':
return 6;
case '5':
return 5;
case '4':
return 4;
case '3':
return 3;
case '2':
return 2;
case '1':
return 1;
case '0':
return 0;
};
std::vector<int> result;
for( auto const & k : s )
{
result.push_back(getint(k));
}
return result;
}
I was wondering if there in another way to do this. I have considered to use something as an std::map as well, but I am uncertain which one might be faster. If there is another way to do this please add it.
Please keep in mind that I am doing this as a code-kata to improve my skills, and learn.
Thanks and TIA!
To start with, you can probably simplify your logic like so:
auto getint = [](char const k){
if(k >= 'a' && k <= 'f') return (k - 'a');
else if(k >= 'A' && k <= 'F') return (k - 'A');
else if(k >= '0' && k <= '9') return (k - '0');
else return -1;
}
Beyond that, there may exist a Standard Library function that does exactly this, which you might prefer depending on your specific needs.
For the decimal digits it's very easy to convert a character to its digit, as the C++ specification says that all digits must be consecutive in all encodings, with '0' being the lowest and '9' the highest. That means you could convert a character to number by just subtracting '0', like e.g. k - '0'. There's no such requirement for the letters though, but the most common encoding (ASCII) the same is true, but it should not be counted on if you want to be portable.
You could also do it using e.g. std::transform and std::back_inserter, so no need for your own loop. Perhaps something like
std::transform(std::begin(s), std::end(s), std::back_inserter(result), getint);
In the getint function you could use e.g. std::isxdigit and std::isdigit to check if the character is a valid hexadecimal or decimal digit, respectively. You should probably be using e.g. std::tolower in case the hexadecimal digits are upper-case.
You can use strtol or strtoll to do most of the heavy lifting for you of converting from a base16 string to an integer value.
Then convert back to a regular string using a stringstream object.
// parse hex string with strtol
long value = ::strtol(s.c_str(), nullptr, 16); //not shown - checking for errors. Read the manual page for more info
// convert value back to base-10 string
std::stringstream st;
st << value;
std::string result = st.str();
return result;

c++ Roman Additive Form Conversion

I'm working in a program that converts from Roman to Decimal. I have to validate 2 things: One that the characters entered are M or D or C or L or X or V or I, in other words valid for processing.
Number two, I have to make sure that bigger characters value go first and if not to print and error message and have the user to try again (this is the part where I am stuck)
For instance, If I wanted to input 9 and I input IX it should display an error message because is not in Additive form. It should be VIIII. How can I code this so it compares characters to know whether bigger letter values are first and so on?
I keep getting incorrect validation.
Is there a way to assign a value to the letters in the string? I'm thinking in comparing them as int values which I know how to and from there validate input format.
void RomanNum::setRomanNumber() //get input and calculate decimal equivalent
{
//I 1, V 5, X 10, L 50, C 100, D 500, M 1000
int value = 0;
string input;
char current, next;
enum validationData { M, D, C, L, X, V, I };
bool validationCharacters = true;
//bool validationAdditiveForm = true;
getline(cin, input, '\n');
for (int i = 0; i < input.length(); i++) //calculate each Roman letter at a time
{
current = input[i];
next = current + 1;
if (current >= validationData(next))
{
switch (input[i])
{
case 'M':
value += 1000;
break;
case 'D':
value += 500;
break;
case 'C':
value += 100;
break;
case 'L':
value += 50;
break;
case 'X':
value += 10;
break;
case 'V':
value += 5;
break;
case 'I':
value += 1;
break;
default:
validationCharacters = false;
break;
}
}
else
{
cout << "\nInvalid order. Bigger values go first\n";
}
}
}
I would recommend a std::map<char, int> to hold the mapping between letetrs and values.
With the map, you can then convert the input string (a sequence of characters) to a sequence of values (std::vector<int>). From there on, it's just a single check to see if the vector is sorted, and a single function call to add up all values. (I'll leave finding the right function as homework)

C++: Hex to Decimal Conversion Function - Not getting correct output

I'm trying to convert hex values to decimal. I'm just trying to extract either a number (0-9) or letter (A-F), which I'm converting to the number value with another function, and then push the values into a stack (I could have used vector, but chose stack this time). I'm then just trying to get the decimal value, and since a stack works backwards, it should be in order.
The correct output, as shown below, should be 1728, but I'm getting 12.
Thanks in advance.
#include <iostream>
#include <string>
#include <math.h>
#include <stack>
using namespace std;
int hexCharToDec(char a);
void hexToDecimal(string str, stack<int> & myStack);
int main(){
stack<int> myStack;
string str = "6C0"; // should be 1728
hexToDecimal(str, myStack);
}
void hexToDecimal(string str, stack<int> & myStack){
int totalVal = 0;
for (int i = 0; i < str.length(); i++){
if (str.at(i) <= 9)
myStack.push(str.at(i));
else if (str.at(i) >= 'A' && str.at(i) <= 'F')
myStack.push(hexCharToDec(str.at(i)));
}
int k = 0;
for (int i = 0; i < myStack.size(); i++){
totalVal += (myStack.top() * pow(16, k++));
myStack.pop();
}
cout << totalVal;
}
int hexCharToDec(char hexChar){
switch(hexChar){
case 'A':
return 10;
break;
case 'B':
return 11;
break;
case 'C':
return 12;
break;
case 'D':
return 13;
break;
case 'E':
return 14;
break;
case 'F':
return 15;
break;
}}
In the original version of the code you posted, you mixed up 0 with '0' and likewise for the other digits. The output was 12 because if you take 6C0 and ignore the 6 and 0, the result is C which is 12.
In the updated version this loop is broken:
for (int i = 0; i < myStack.size(); i++)
{
totalVal += (myStack.top() * pow(16, i));
myStack.pop();
}
When you do pop(), it reduces size(). So you only actually process half of the digits in the stack (rounded up). To fix this, loop until myStack.size() == 0 instead.
The problem is that the characters you're inputting aren't in the range of your if statements. The digit characters don't have the values 0-9, they are '0'-'9' - a different thing altogether. Those characters don't get processed at all.
In addition, your for loop is looping over the size of the stack - but the size of the stack is changing as you pop things off the end. You're only processing half of the input.
A working solution:
#include<iostream>
#include <string>
#include <sstream>
int main()
{
int n;
string str = "6C0";
istringstream sin(str);
sin>>hex>>n;
cout<<n<<endl;
return 0;
}